Image Pixel.cpp 202 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111
  1. /******************************************************************************
  2. 'CubicFastSharp' is equal to 'Lerp4Weights' in following way:
  3. const int n=100; REP(n)
  4. {
  5. Flt step=i/Flt(n-1);
  6. Vec4 w; Lerp4Weights(w, step);
  7. Flt c=CubicFastSharp(step*2);
  8. Vec2(step*0.5f+0.5f, w.x).draw(RED);
  9. Vec2(step*0.5f , w.y).draw(GREEN);
  10. Vec2(step , c ).draw(BLUE);
  11. }
  12. Upscaling should be done in sRGB Gamma space to allow for smooth gradients - looks much better !!
  13. After many tests for creating mip maps REP(3)image.downSample(FILTER_DOWN);
  14. it was noticed that doing Gamma Correct filtering does not improve quality significantly, as FILTER_DOWN has sharpening filter which already makes it look good.
  15. Using Gamma Correct filtering made bigger difference for image.resize(image.w()/8, image.h()/8) though
  16. /******************************************************************************/
  17. #include "stdafx.h"
  18. namespace EE{
  19. #include "Import/BC.h"
  20. #include "Import/ETC.h"
  21. #define SUPPORT_DEPTH_TO_COLOR 0
  22. #define ALPHA_LIMIT 0.0625f // alpha limit at which colors start to blend to RGB, warning: if increasing this value then it might cause overflow for integer processing (for 'CWA8AlphaLimit')
  23. /*
  24. Flt CW[8][8];
  25. Int smallest=-1; Flt dist=0;
  26. for(Int i=1; i<34984; i++)
  27. {
  28. Flt d=0;
  29. REPD(y, 8)
  30. {
  31. Flt fy2=Sqr(-1.75f+0.5f*y);
  32. REPD(x, 8)
  33. {
  34. Flt fx2=Sqr(-1.75f+0.5f*x), w=Cubic(Sqrt(fx2+fy2));
  35. CW[y][x]=w/0.00417041779f*i;
  36. MAX(d, Abs(Round(CW[y][x])-CW[y][x]));
  37. }
  38. }
  39. if(smallest<0 || d<dist)
  40. {
  41. Long sum=0; REPD(y, 8)REPD(x, 8)sum+=255*CW[y][x];
  42. if(sum<0x7FFFFFFF){dist=d; smallest=i;}
  43. }
  44. if(smallest==1321)
  45. {
  46. Long sum=0;
  47. REPD(y, 8)
  48. REPD(x, 8)sum+=255*CW[y][x];
  49. Int x=CW[4][4];
  50. x*=255; // color
  51. x*=255; // alpha
  52. x*=64;
  53. Str s;
  54. s.line()+=S+"static const Int CW8Sum="+sum+"/255;";
  55. s.line()+=S+"static const Int CW8[8][8]={";
  56. FREPD(y, 8)
  57. {
  58. s.line()+=" {";
  59. FREPD(x, 8)
  60. {
  61. if(x)s+=", ";
  62. s+=Round(CW[y][x]);
  63. }
  64. s+="},";
  65. }
  66. s.line()+="};";
  67. ClipSet(s.line());
  68. }
  69. }
  70. Flt CWA[8][8];
  71. Int sum=0;
  72. REPD(y, 8)
  73. {
  74. Flt fy2=Sqr(-1.75f+0.5f*y);
  75. REPD(x, 8)
  76. {
  77. Flt fx2=Sqr(-1.75f+0.5f*x), w=Cubic(Sqrt(fx2+fy2));
  78. CWA[y][x]=w*0xFF08/2.9391276836395264;
  79. sum+=Round(CWA[y][x]);
  80. }
  81. }
  82. Int s=sum;
  83. Dbl CFSMW8[8][8], W=0;
  84. REPD(y, 8)
  85. {
  86. Dbl fy2=Sqr(-1.75+0.5*y);
  87. REPD(x, 8)
  88. {
  89. Dbl fx2=Sqr(-1.75+0.5*x), w=fx2+fy2; w=((w<Sqr(CUBIC_FAST_RANGE)) ? CubicFastSmooth(Sqrt(w)) : 0);
  90. W+=w;
  91. CFSMW8[y][x]=w;
  92. }
  93. }
  94. REPD(y, 8)
  95. REPD(x, 8)CFSMW8[y][x]/=W;
  96. Str s;
  97. s.line()+=S+"static const Flt CFSMW8[8][8]= // [y][x]";
  98. s.line()+='{';
  99. FREPD(y, 8)
  100. {
  101. s.line()+=" {";
  102. FREPD(x, 8)
  103. {
  104. if(x)s+=", ";
  105. s+=CFSMW8[y][x]; s+='f';
  106. }
  107. s+="},";
  108. }
  109. s.line()+="};";
  110. ClipSet(s.line());
  111. */
  112. static const Int CW8Sum=237400608/255;
  113. static const Int CW8[8][8]={
  114. {0, 0, -1321, -6558, -6558, -1321, 0, 0},
  115. {0, -6558, -21317, -22888, -22888, -21317, -6558, 0},
  116. {-1321, -21317, -8477, 56591, 56591, -8477, -21317, -1321},
  117. {-6558, -22888, 56591, 238767, 238767, 56591, -22888, -6558},
  118. {-6558, -22888, 56591, 238767, 238767, 56591, -22888, -6558},
  119. {-1321, -21317, -8477, 56591, 56591, -8477, -21317, -1321},
  120. {0, -6558, -21317, -22888, -22888, -21317, -6558, 0},
  121. {0, 0, -1321, -6558, -6558, -1321, 0, 0},
  122. };
  123. static const Int CWA8Sum=5571097/255;
  124. static const Int CWA8AlphaLimit=CWA8Sum*255*ALPHA_LIMIT;
  125. static const Int CWA8[8][8]={
  126. {0, 0, -31, -154, -154, -31, 0, 0},
  127. {0, -154, -500, -537, -537, -500, -154, 0},
  128. {-31, -500, -199, 1328, 1328, -199, -500, -31},
  129. {-154, -537, 1328, 5603, 5603, 1328, -537, -154},
  130. {-154, -537, 1328, 5603, 5603, 1328, -537, -154},
  131. {-31, -500, -199, 1328, 1328, -199, -500, -31},
  132. {0, -154, -500, -537, -537, -500, -154, 0},
  133. {0, 0, -31, -154, -154, -31, 0, 0},
  134. };
  135. static const Flt CFSMW8[8][8]= // [y][x]
  136. {
  137. {0.000000000f, 0.000000000f, 0.000025184f, 0.000355931f, 0.000355931f, 0.000025184f, 0.000000000f, 0.000000000f},
  138. {0.000000000f, 0.000355931f, 0.004531289f, 0.010840487f, 0.010840487f, 0.004531289f, 0.000355931f, 0.000000000f},
  139. {0.000025184f, 0.004531289f, 0.023553867f, 0.049229048f, 0.049229048f, 0.023553867f, 0.004531289f, 0.000025184f},
  140. {0.000355931f, 0.010840487f, 0.049229048f, 0.096126321f, 0.096126321f, 0.049229048f, 0.010840487f, 0.000355931f},
  141. {0.000355931f, 0.010840487f, 0.049229048f, 0.096126321f, 0.096126321f, 0.049229048f, 0.010840487f, 0.000355931f},
  142. {0.000025184f, 0.004531289f, 0.023553867f, 0.049229048f, 0.049229048f, 0.023553867f, 0.004531289f, 0.000025184f},
  143. {0.000000000f, 0.000355931f, 0.004531289f, 0.010840487f, 0.010840487f, 0.004531289f, 0.000355931f, 0.000000000f},
  144. {0.000000000f, 0.000000000f, 0.000025184f, 0.000355931f, 0.000355931f, 0.000025184f, 0.000000000f, 0.000000000f},
  145. };
  146. #define J1 PLATFORM(_j1, j1)
  147. /******************************************************************************/
  148. // SRGB
  149. /******************************************************************************/
  150. static Flt SRGBToLinearArray[256];
  151. static Byte LinearToSRGBArray[3139]; // 3139=smallest array size which preserves "LinearToSRGBFast(SRGBToLinearFast(s))==s"
  152. static Flt ByteSRGBToLinear(Byte s) {return SRGBToLinear(s/255.0f) ;} // convert 0..255 srgb to 0..1 linear
  153. static Byte LinearToByteSRGB(Flt l) {return FltToByte(LinearToSRGB(l ));} // convert 0..1 linear to 0..255 srgb
  154. static INLINE Flt SRGBToLinearFast(Byte s) {return SRGBToLinearArray[s];}
  155. static Byte LinearToSRGBFast(Flt l) {return LinearToSRGBArray[Mid(RoundPos(l*(Elms(LinearToSRGBArray)-1)), 0, Elms(LinearToSRGBArray)-1)];}
  156. void InitSRGB()
  157. {
  158. REPAO(SRGBToLinearArray)=ByteSRGBToLinear(i);
  159. REPAO(LinearToSRGBArray)=LinearToByteSRGB(i/Flt(Elms(LinearToSRGBArray)-1));
  160. #if DEBUG && 0 // do some debug checks
  161. FREP(Elms(SRGBToLinearArray)-1)DYNAMIC_ASSERT(SRGBToLinearArray[i]<=SRGBToLinearArray[i+1], "SRGBToLinearArray[i] > SRGBToLinearArray[i+1]");
  162. FREP(Elms(LinearToSRGBArray)-1)DYNAMIC_ASSERT(LinearToSRGBArray[i]<=LinearToSRGBArray[i+1], "LinearToSRGBArray[i] > LinearToSRGBArray[i+1]");
  163. FREP( 256)DYNAMIC_ASSERT(LinearToSRGBFast(SRGBToLinearFast(i))==i , "LinearToSRGBFast(SRGBToLinearFast(s))!=s");
  164. #if 0
  165. Str s;
  166. s.line(); FREPA(SRGBToLinearArray)s.space()+=SRGBToLinearArray[i];
  167. s.line(); FREPA(SRGBToLinearArray)s.space()+=LinearToByteSRGB(SRGBToLinearArray[i])-LinearToSRGBFast(SRGBToLinearArray[i]);
  168. Exit(s);
  169. #endif
  170. #endif
  171. }
  172. #if 0 // approximate functions
  173. /*
  174. Error was calculated using:
  175. Flt d0=0; Int d1=0;
  176. REP(256)
  177. {
  178. Flt f=i/255.0f,
  179. l1=ByteSRGBToLinear (i),
  180. l2=SRGBToLinearApprox(i);
  181. Byte s1=LinearToByteSRGB (f),
  182. s2=LinearToSRGBApprox(f);
  183. d0+=Abs(l1-l2);
  184. d1+=Abs(s1-s2);
  185. }
  186. Exit(S+d0/256+' '+d1/255.0f/256);
  187. */
  188. #define SRGB_MODE 0
  189. static Flt SRGBToLinearApprox(Byte s)
  190. {
  191. Flt f=s/255.0f;
  192. #if SRGB_MODE==0 // average error = 0.023
  193. return Sqr(f);
  194. #elif SRGB_MODE==1 // average error = 0.004
  195. return Pow(f, 2.2f);
  196. #else // average error = 0.001
  197. return f*(f*(f*0.305306011f+0.682171111f)+0.012522878f);
  198. #endif
  199. }
  200. static Byte LinearToSRGBApprox(Flt l)
  201. {
  202. if(l<=0)return 0;
  203. #if SRGB_MODE==0 // average error = 0.023
  204. Flt s=SqrtFast(l);
  205. #elif SRGB_MODE==1 // average error = 0.004
  206. Flt s=Pow(l, 1/2.2f);
  207. #else // average error = 0.001
  208. Flt s1=SqrtFast(l),
  209. s2=SqrtFast(s1),
  210. s3=SqrtFast(s2),
  211. s =0.585122381f*s1 + 0.783140355f * s2 - 0.368262736f*s3;
  212. #endif
  213. return Min(RoundPos(s*255.0f), 255);
  214. }
  215. #endif
  216. /******************************************************************************/
  217. // FILTERING
  218. /******************************************************************************/
  219. static Flt Linear(Flt x) {ABS(x); if(x>=1)return 0; return 1-x;}
  220. /******************************************************************************/
  221. #define CEIL(x) int(x+0.99f)
  222. ASSERT(CEIL(0.0f)==0);
  223. ASSERT(CEIL(0.4f)==1);
  224. ASSERT(CEIL(0.5f)==1);
  225. ASSERT(CEIL(0.6f)==1);
  226. ASSERT(CEIL(0.9f)==1);
  227. ASSERT(CEIL(1.0f)==1);
  228. ASSERT(CEIL(1.1f)==2);
  229. #define CUBIC_FAST_RANGE 2
  230. #define CUBIC_FAST_SAMPLES CEIL(CUBIC_FAST_RANGE)
  231. #define CUBIC_MED_SHARPNESS (2/2.5f) // (2/2.65f) is smooth and correctly works with gradients, but (2/2.5f) is sharper and looks like JincJinc for regular images
  232. #define CUBIC_SHARP_SHARPNESS (2/2.5f) // (2/2.65f) is smooth and correctly works with gradients, but (2/2.5f) is sharper and looks like JincJinc for regular images
  233. #define CUBIC_MED_RANGE (2/CUBIC_MED_SHARPNESS )
  234. #define CUBIC_SHARP_RANGE (2/CUBIC_SHARP_SHARPNESS)
  235. #define CUBIC_MED_SAMPLES CEIL(CUBIC_MED_RANGE )
  236. #define CUBIC_SHARP_SAMPLES CEIL(CUBIC_SHARP_RANGE )
  237. static INLINE Flt Cubic(Flt x, const Flt blur, const Flt sharpen)
  238. {
  239. Flt x2=x*x,
  240. x3=x*x*x;
  241. return (x<=1) ? ((12-9*blur-6*sharpen)/6*x3 + (-18+12*blur+6*sharpen)/6*x2 + (6-2*blur )/6)
  242. : ((-blur-6*sharpen )/6*x3 + (6*blur+30*sharpen )/6*x2 + (-12*blur-48*sharpen)/6*x + (8*blur+24*sharpen)/6);
  243. }
  244. static INLINE Flt CatmullRom (Flt x) {return Cubic(x, 0.0f , 0.5f );}
  245. static INLINE Flt MitchellNetravali(Flt x) {return Cubic(x, 1.0f/3, 1.0f/3);}
  246. static INLINE Flt Robidoux (Flt x) {return Cubic(x, 12/(19+9*SQRT2), 113/(58+216*SQRT2));}
  247. static INLINE Flt RobidouxSharp (Flt x) {return Cubic(x, 6/(13+7*SQRT2), 7/( 2+ 12*SQRT2));}
  248. static INLINE Flt CubicFast (Flt x) {return Cubic(x, 1.0f/3, 1.0f/3);}
  249. static INLINE Flt CubicFastSmooth(Flt x) {return Cubic(x, 1.0f , 0.000f);}
  250. static INLINE Flt CubicFastSharp (Flt x) {return Cubic(x, 0.0f , 0.500f);}
  251. static INLINE Flt CubicMed (Flt x) {return Cubic(x, 0.0f , 0.400f);}
  252. static INLINE Flt CubicSharp (Flt x) {return Cubic(x, 0.0f , 0.500f);}
  253. static Flt CubicFast2 (Flt xx) {return CubicFast (SqrtFast(xx));}
  254. static Flt CubicFastSmooth2(Flt xx) {return CubicFastSmooth(SqrtFast(xx));}
  255. static Flt CubicFastSharp2 (Flt xx) {return CubicFastSharp (SqrtFast(xx));}
  256. static Flt CubicMed2 (Flt xx) {return CubicMed (SqrtFast(xx));}
  257. static Flt CubicSharp2 (Flt xx) {return CubicSharp (SqrtFast(xx));}
  258. /******************************************************************************/
  259. #define SINC_RANGE 2
  260. #define JINC_HALF_RANGE 1.2196698912665045f
  261. #define JINC_RANGE 2.233130455f
  262. #define JINC_SMOOTH 0.42f // 0.0 (sharp) .. 0.5 (smooth)
  263. #define JINC_SAMPLES CEIL(JINC_RANGE)
  264. //static inline Flt sinc(Flt x) {return x ? sin(x)/x : 1.0f;}
  265. //static inline Flt jinc(Flt x) {return x ? j1(x)/x : 0.5f;}
  266. static INLINE Flt SincSinc(Flt x)
  267. {
  268. //return Sinc(x)*Sinc(x*JINC_SMOOTH);
  269. x*=PI; Flt xx=Sqr(x); return xx ? Sin(x)*Sin(x*JINC_SMOOTH)/xx : JINC_SMOOTH;
  270. }
  271. static INLINE Flt JincJinc(Flt x)
  272. {
  273. //return Jinc(x)*Jinc(x*JINC_SMOOTH);
  274. x*=PI; Flt xx=Sqr(x); return xx ? J1(x)*J1(x*JINC_SMOOTH)/xx : 0.25f*JINC_SMOOTH;
  275. }
  276. static Flt SincSinc2(Flt xx) {return SincSinc(SqrtFast(xx));}
  277. static Flt JincJinc2(Flt xx) {return JincJinc(SqrtFast(xx));}
  278. /******************************************************************************/
  279. static void Add(Vec4 &color, Vec &rgb, C Vec4 &sample, Bool alpha_weight) // here 'weight'=1
  280. {
  281. if(alpha_weight)
  282. {
  283. rgb +=sample.xyz ; // RGB
  284. color.xyz+=sample.xyz*sample.w; // RGB*Alpha
  285. color.w += sample.w; // Alpha
  286. }else color +=sample ;
  287. }
  288. static void Add(Vec4 &color, Vec &rgb, C Vec4 &sample, Flt weight, Bool alpha_weight)
  289. {
  290. if(alpha_weight)
  291. {
  292. rgb +=sample.xyz*weight; // RGB* weight
  293. weight *=sample.w ; // adjust 'weight' by Alpha
  294. color.xyz+=sample.xyz*weight; // RGB*Alpha*weight
  295. color.w += weight; // Alpha*weight
  296. }else color +=sample *weight;
  297. }
  298. static void Normalize(Vec4 &color, C Vec &rgb, Bool alpha_weight, Bool high_precision) // here 'weight'=1
  299. {
  300. if(alpha_weight)
  301. {
  302. // normalize
  303. if(color.w>0)color.xyz/=color.w;
  304. // for low opacities we need to preserve the original RGB, because, at opacity=0 RGB information is totally lost, and because the image may be used for drawing, in which case the GPU will use bilinear filtering, and we need to make sure that mostly transparent pixel RGB values aren't artificially upscaled too much, also because at low opacities the alpha precision is low (because normally images are in 8-bit format, and we get alpha values like 1,2,3,..) and because we need to divide by alpha, inaccuracies may occur
  305. if(color.w<ALPHA_LIMIT)
  306. {
  307. if(color.w<=0)
  308. {
  309. color.w=0; // 'color.w' can be negative due to sharpening
  310. color.xyz=rgb;
  311. }else
  312. if(!high_precision) // no need to do this for high precision
  313. {
  314. Flt blend=color.w/ALPHA_LIMIT; // color.xyz = Lerp(rgb, color.xyz, blend);
  315. color.xyz*=blend;
  316. color.xyz+=rgb*(1-blend);
  317. }
  318. }
  319. }
  320. }
  321. static void Normalize(Vec4 &color, C Vec &rgb, Flt weight, Bool alpha_weight, Bool high_precision) // warning: 'weight' must be non-zero
  322. {
  323. if(alpha_weight)
  324. {
  325. // normalize
  326. if(color.w>0)
  327. {
  328. color.xyz/=color.w;
  329. color.w /=weight;
  330. }
  331. // for low opacities we need to preserve the original RGB, because, at opacity=0 RGB information is totally lost, and because the image may be used for drawing, in which case the GPU will use bilinear filtering, and we need to make sure that mostly transparent pixel RGB values aren't artificially upscaled too much, also because at low opacities the alpha precision is low (because normally images are in 8-bit format, and we get alpha values like 1,2,3,..) and because we need to divide by alpha, inaccuracies may occur
  332. if(color.w<ALPHA_LIMIT)
  333. {
  334. if(color.w<=0)
  335. {
  336. color.w=0; // 'color.w' can be negative due to sharpening
  337. color.xyz=rgb/weight;
  338. }else
  339. if(!high_precision) // no need to do this for high precision
  340. {
  341. Flt blend=color.w/ALPHA_LIMIT; // color.xyz = Lerp(rgb, color.xyz, blend);
  342. color.xyz*=blend;
  343. color.xyz+=rgb*((1-blend)/weight);
  344. }
  345. }
  346. }else color/=weight;
  347. }
  348. /******************************************************************************/
  349. // PIXEL / COLOR
  350. /******************************************************************************/
  351. void Image::pixel(Int x, Int y, UInt pixel)
  352. {
  353. if(InRange(x, lw()) && InRange(y, lh()) && !compressed()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  354. {
  355. Byte *data=T.data() + x*bytePP() + y*pitch();
  356. switch(bytePP())
  357. {
  358. case 1: (*(U8 *)data)=pixel&0xFF; break;
  359. case 2: (*(U16*)data)=pixel&0xFFFF; break;
  360. case 3: (*(U16*)data)=pixel&0xFFFF; data[2]=(pixel>>16)&0xFF; break;
  361. case 4: (*(U32*)data)=pixel; break;
  362. }
  363. }
  364. }
  365. /******************************************************************************/
  366. void Image::pixel3D(Int x, Int y, Int z, UInt pixel)
  367. {
  368. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld()) && !compressed()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  369. {
  370. Byte *data=T.data() + x*bytePP() + y*pitch() + z*pitch2();
  371. switch(bytePP())
  372. {
  373. case 1: (*(U8 *)data)=pixel&0xFF; break;
  374. case 2: (*(U16*)data)=pixel&0xFFFF; break;
  375. case 3: (*(U16*)data)=pixel&0xFFFF; data[2]=(pixel>>16)&0xFF; break;
  376. case 4: (*(U32*)data)=pixel; break;
  377. }
  378. }
  379. }
  380. /******************************************************************************/
  381. UInt Image::pixel(Int x, Int y)C
  382. {
  383. if(InRange(x, lw()) && InRange(y, lh()) && !compressed()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  384. {
  385. C Byte *data=T.data() + x*bytePP() + y*pitch();
  386. switch(bytePP())
  387. {
  388. case 1: return *(U8 *)data;
  389. case 2: return *(U16*)data;
  390. case 3: return *(U16*)data | (data[2]<<16);
  391. case 4: return *(U32*)data;
  392. }
  393. }
  394. return 0;
  395. }
  396. /******************************************************************************/
  397. UInt Image::pixel3D(Int x, Int y, Int z)C
  398. {
  399. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld()) && !compressed()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  400. {
  401. C Byte *data=T.data() + x*bytePP() + y*pitch() + z*pitch2();
  402. switch(bytePP())
  403. {
  404. case 1: return *(U8 *)data;
  405. case 2: return *(U16*)data;
  406. case 3: return *(U16*)data | (data[2]<<16);
  407. case 4: return *(U32*)data;
  408. }
  409. }
  410. return 0;
  411. }
  412. /******************************************************************************/
  413. static void SetPixelF(Byte *data, IMAGE_TYPE type, Flt pixel)
  414. {
  415. switch(type)
  416. {
  417. case IMAGE_F32 : (*(Flt *)data)=pixel; break;
  418. case IMAGE_F32_2: (*(Vec2*)data)=pixel; break;
  419. case IMAGE_F32_3: (*(Vec *)data)=pixel; break;
  420. case IMAGE_F32_4: (*(Vec4*)data)=pixel; break;
  421. case IMAGE_F16 : {U16 *d=(U16*)data; d[0]= Half(pixel).data;} break;
  422. case IMAGE_F16_2: {U16 *d=(U16*)data; d[0]=d[1]= Half(pixel).data;} break;
  423. case IMAGE_F16_3: {U16 *d=(U16*)data; d[0]=d[1]=d[2]= Half(pixel).data;} break;
  424. case IMAGE_F16_4: {U16 *d=(U16*)data; d[0]=d[1]=d[2]=d[3]=Half(pixel).data;} break;
  425. case IMAGE_R8G8B8X8:
  426. case IMAGE_B8G8R8X8:
  427. case IMAGE_B8G8R8A8:
  428. case IMAGE_R8G8B8A8: {VecB4 &v=*(VecB4*)data; v.x=v.y=v.z=FltToByte(pixel); v.w=255;} break;
  429. case IMAGE_B8G8R8 :
  430. case IMAGE_R8G8B8 : {VecB &v=*(VecB *)data; v.x=v.y=v.z=FltToByte(pixel);} break;
  431. case IMAGE_R8G8 : {VecB2 &v=*(VecB2*)data; v.x=v.y= FltToByte(pixel);} break;
  432. case IMAGE_R8_SIGN : {Byte &v=*(Byte *)data; v = SFltToSByte(pixel); } break;
  433. case IMAGE_R8G8_SIGN : {VecB2 &v=*(VecB2*)data; v.x=v.y= SFltToSByte(pixel); } break;
  434. case IMAGE_R8G8B8A8_SIGN: {VecB4 &v=*(VecB4*)data; v.x=v.y=v.z=SFltToSByte(pixel); v.w=255;} break;
  435. case IMAGE_R10G10B10A2: {UInt v=Mid(RoundPos(pixel*0x3FF), 0, 0x3FF); (*(UInt*)data)=v|(v<<10)|(v<<20)|(3<<30);} break;
  436. case IMAGE_R8 :
  437. case IMAGE_A8 :
  438. case IMAGE_L8 :
  439. case IMAGE_I8 : (*(U8 *)data)=FltToByte( pixel) ; break; // it's okay to clamp int for small values
  440. case IMAGE_I16: (*(U16*)data)=RoundU(Sat(pixel)*0x0000FFFFu); break; // it's better to clamp flt for bigger values
  441. case IMAGE_I32: (*(U32*)data)=RoundU(Sat(pixel)*0xFFFFFFFFu); break; // it's better to clamp flt for bigger values
  442. case IMAGE_I24: { U32 c =RoundU(Sat(pixel)*0x00FFFFFFu); (*(U16*)data)=c; data[2]=(c>>16);} break; // it's better to clamp flt for bigger values
  443. }
  444. }
  445. void Image::pixelF(Int x, Int y, Flt pixel)
  446. {
  447. if(InRange(x, lw()) && InRange(y, lh()) && !compressed()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  448. SetPixelF(data() + x*bytePP() + y*pitch(), hwType(), pixel);
  449. }
  450. /******************************************************************************/
  451. void Image::pixel3DF(Int x, Int y, Int z, Flt pixel)
  452. {
  453. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld()) && !compressed()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  454. SetPixelF(data() + x*bytePP() + y*pitch() + z*pitch2(), hwType(), pixel);
  455. }
  456. /******************************************************************************/
  457. Flt Image::pixelF(Int x, Int y)C
  458. {
  459. if(InRange(x, lw()) && InRange(y, lh())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  460. {
  461. C Byte *data=T.data() + x*bytePP() + y*pitch();
  462. switch(hwType())
  463. {
  464. case IMAGE_F32 : return *(Flt*)data;
  465. case IMAGE_F32_2: return *(Flt*)data;
  466. case IMAGE_F32_3: return *(Flt*)data;
  467. case IMAGE_F32_4: return *(Flt*)data;
  468. case IMAGE_F16 : return *(Half*)data;
  469. case IMAGE_F16_2: return *(Half*)data;
  470. case IMAGE_F16_3: return *(Half*)data;
  471. case IMAGE_F16_4: return *(Half*)data;
  472. case IMAGE_B8G8R8 :
  473. case IMAGE_B8G8R8X8:
  474. case IMAGE_B8G8R8A8: return ((VecB4*)data)->z/Flt(0xFF);
  475. case IMAGE_R8 :
  476. case IMAGE_R8G8 :
  477. case IMAGE_R8G8B8 :
  478. case IMAGE_R8G8B8X8:
  479. case IMAGE_R8G8B8A8:
  480. case IMAGE_A8 :
  481. case IMAGE_L8 :
  482. case IMAGE_L8A8 :
  483. case IMAGE_I8 : return (*(U8*)data)/Flt(0x000000FFu);
  484. case IMAGE_D16: if(GL)return (*(U16*)data)/Flt(0x0000FFFFu)*2-1; // !! else fall through no break on purpose !!
  485. case IMAGE_I16: return (*(U16*)data)/Flt(0x0000FFFFu);
  486. case IMAGE_D32 : return GL ? (*(Flt*)data)*2-1 : *(Flt*)data;
  487. //case IMAGE_D32I: if(GL)return (*(U32*)data)/Dbl(0xFFFFFFFFu)*2-1; // !! else fall through no break on purpose !!
  488. case IMAGE_I32 : return (*(U32*)data)/Dbl(0xFFFFFFFFu); // Dbl required to get best precision
  489. case IMAGE_D24S8:
  490. case IMAGE_D24X8: if(GL)return (*(U16*)(data+1) | (data[3]<<16))/Flt(0x00FFFFFFu)*2-1; // !! else fall through no break on purpose !!
  491. case IMAGE_I24 : return (*(U16*) data | (data[2]<<16))/Flt(0x00FFFFFFu) ; // here Dbl is not required, this was tested
  492. case IMAGE_R10G10B10A2: return ((*(UInt*)data)&0x3FF)/Flt(0x3FF);
  493. case IMAGE_R8_SIGN :
  494. case IMAGE_R8G8_SIGN :
  495. case IMAGE_R8G8B8A8_SIGN: return SByteToSFlt(*(U8*)data);
  496. case IMAGE_BC1 :
  497. case IMAGE_BC2 :
  498. case IMAGE_BC3 :
  499. case IMAGE_BC7 :
  500. case IMAGE_PVRTC1_2:
  501. case IMAGE_PVRTC1_4:
  502. case IMAGE_ETC1 :
  503. case IMAGE_ETC2 :
  504. case IMAGE_ETC2_A1 :
  505. case IMAGE_ETC2_A8 : return decompress(x, y).r/255.0f;
  506. case IMAGE_B4G4R4X4: return (((*(U16*)data)>> 8)&0x0F)/15.0f;
  507. case IMAGE_B4G4R4A4: return (((*(U16*)data)>> 8)&0x0F)/15.0f;
  508. case IMAGE_B5G5R5X1: return (((*(U16*)data)>>10)&0x1F)/31.0f;
  509. case IMAGE_B5G5R5A1: return (((*(U16*)data)>>10)&0x1F)/31.0f;
  510. case IMAGE_B5G6R5 : return (((*(U16*)data)>>11)&0x1F)/31.0f;
  511. }
  512. }
  513. return 0;
  514. }
  515. /******************************************************************************/
  516. Flt Image::pixel3DF(Int x, Int y, Int z)C
  517. {
  518. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  519. {
  520. C Byte *data=T.data() + x*bytePP() + y*pitch() + z*pitch2();
  521. switch(hwType())
  522. {
  523. case IMAGE_F32 : return *(Flt*)data;
  524. case IMAGE_F32_2: return *(Flt*)data;
  525. case IMAGE_F32_3: return *(Flt*)data;
  526. case IMAGE_F32_4: return *(Flt*)data;
  527. case IMAGE_F16 : return *(Half*)data;
  528. case IMAGE_F16_2: return *(Half*)data;
  529. case IMAGE_F16_3: return *(Half*)data;
  530. case IMAGE_F16_4: return *(Half*)data;
  531. case IMAGE_B8G8R8 :
  532. case IMAGE_B8G8R8X8:
  533. case IMAGE_B8G8R8A8: return ((VecB4*)data)->z/Flt(0xFF);
  534. case IMAGE_R8 :
  535. case IMAGE_R8G8 :
  536. case IMAGE_R8G8B8 :
  537. case IMAGE_R8G8B8X8:
  538. case IMAGE_R8G8B8A8:
  539. case IMAGE_A8 :
  540. case IMAGE_L8 :
  541. case IMAGE_L8A8 :
  542. case IMAGE_I8 : return (*(U8*)data)/Flt(0x000000FFu);
  543. case IMAGE_D16: if(GL)return (*(U16*)data)/Flt(0x0000FFFFu)*2-1; // !! else fall through no break on purpose !!
  544. case IMAGE_I16: return (*(U16*)data)/Flt(0x0000FFFFu);
  545. case IMAGE_D32 : return GL ? (*(Flt*)data)*2-1 : *(Flt*)data;
  546. //case IMAGE_D32I: if(GL)return (*(U32*)data)/Dbl(0xFFFFFFFFu)*2-1; // !! else fall through no break on purpose !!
  547. case IMAGE_I32 : return (*(U32*)data)/Dbl(0xFFFFFFFFu); // Dbl required to get best precision
  548. case IMAGE_D24S8:
  549. case IMAGE_D24X8: if(GL)return (*(U16*)(data+1) | (data[3]<<16))/Flt(0x00FFFFFFu)*2-1; // !! else fall through no break on purpose !!
  550. case IMAGE_I24 : return (*(U16*) data | (data[2]<<16))/Flt(0x00FFFFFFu) ; // here Dbl is not required, this was tested
  551. case IMAGE_R10G10B10A2: return ((*(UInt*)data)&0x3FF)/Flt(0x3FF);
  552. case IMAGE_R8_SIGN :
  553. case IMAGE_R8G8_SIGN :
  554. case IMAGE_R8G8B8A8_SIGN: return SByteToSFlt(*(U8*)data);
  555. case IMAGE_BC1 :
  556. case IMAGE_BC2 :
  557. case IMAGE_BC3 :
  558. case IMAGE_BC7 :
  559. case IMAGE_PVRTC1_2:
  560. case IMAGE_PVRTC1_4:
  561. case IMAGE_ETC1 :
  562. case IMAGE_ETC2 :
  563. case IMAGE_ETC2_A1 :
  564. case IMAGE_ETC2_A8 : return decompress3D(x, y, z).r/255.0f;
  565. case IMAGE_B4G4R4X4: return (((*(U16*)data)>> 8)&0x0F)/15.0f;
  566. case IMAGE_B4G4R4A4: return (((*(U16*)data)>> 8)&0x0F)/15.0f;
  567. case IMAGE_B5G5R5X1: return (((*(U16*)data)>>10)&0x1F)/31.0f;
  568. case IMAGE_B5G5R5A1: return (((*(U16*)data)>>10)&0x1F)/31.0f;
  569. case IMAGE_B5G6R5 : return (((*(U16*)data)>>11)&0x1F)/31.0f;
  570. }
  571. }
  572. return 0;
  573. }
  574. /******************************************************************************/
  575. static void SetColorF(Byte *data, IMAGE_TYPE type, C Vec4 &color)
  576. {
  577. switch(type)
  578. {
  579. case IMAGE_F32 : (*(Flt *)data)=color.x ; break;
  580. case IMAGE_F32_2: (*(Vec2*)data)=color.xy ; break;
  581. case IMAGE_F32_3: (*(Vec *)data)=color.xyz; break;
  582. case IMAGE_F32_4: (*(Vec4*)data)=color ; break;
  583. case IMAGE_F16 : (*(Half *)data)=color.x ; break;
  584. case IMAGE_F16_2: (*(VecH2*)data)=color.xy ; break;
  585. case IMAGE_F16_3: (*(VecH *)data)=color.xyz; break;
  586. case IMAGE_F16_4: (*(VecH4*)data)=color ; break;
  587. case IMAGE_A8 : (*(U8 *)data)=FltToByte( color.w ); break; // it's okay to clamp int for small values
  588. case IMAGE_L8 : (*(U8 *)data)=FltToByte( color.xyz.max() ); break; // it's okay to clamp int for small values
  589. case IMAGE_I8 : (*(U8 *)data)=FltToByte( color.x ); break; // it's okay to clamp int for small values
  590. case IMAGE_I16: (*(U16*)data)=RoundU(Sat(color.x)*0x0000FFFFu); break; // it's better to clamp flt for bigger values
  591. case IMAGE_I32: (*(U32*)data)=RoundU(Sat(color.x)*0xFFFFFFFFu); break; // it's better to clamp flt for bigger values
  592. case IMAGE_I24: { U32 c =RoundU(Sat(color.x)*0x00FFFFFFu); (*(U16*)data)=c; data[2]=(c>>16);} break; // it's better to clamp flt for bigger values
  593. case IMAGE_L8A8: ((VecB2*)data)->set(FltToByte(color.xyz.max()), FltToByte(color.w)); break;
  594. case IMAGE_B8G8R8A8: ((VecB4*)data)->set(FltToByte(color.z), FltToByte(color.y), FltToByte(color.x), FltToByte(color.w)); break;
  595. case IMAGE_R8G8B8A8: ((VecB4*)data)->set(FltToByte(color.x), FltToByte(color.y), FltToByte(color.z), FltToByte(color.w)); break;
  596. case IMAGE_R8G8B8 : ((VecB *)data)->set(FltToByte(color.x), FltToByte(color.y), FltToByte(color.z) ); break;
  597. case IMAGE_R8G8 : ((VecB2*)data)->set(FltToByte(color.x), FltToByte(color.y) ); break;
  598. case IMAGE_R8 : *(Byte *)data = FltToByte(color.x) ; break;
  599. case IMAGE_B8G8R8 : ((VecB *)data)->set(FltToByte(color.z), FltToByte(color.y), FltToByte(color.x) ); break;
  600. case IMAGE_B8G8R8X8: ((VecB4*)data)->set(FltToByte(color.z), FltToByte(color.y), FltToByte(color.x), 255); break;
  601. case IMAGE_R8G8B8X8: ((VecB4*)data)->set(FltToByte(color.x), FltToByte(color.y), FltToByte(color.z), 255); break;
  602. case IMAGE_R8_SIGN : (*(Byte *)data)= SFltToSByte(color.x) ; break;
  603. case IMAGE_R8G8_SIGN : ( (VecB2*)data)->set(SFltToSByte(color.x), SFltToSByte(color.y) ); break;
  604. case IMAGE_R8G8B8A8_SIGN: ( (VecB4*)data)->set(SFltToSByte(color.x), SFltToSByte(color.y), SFltToSByte(color.z), SFltToSByte(color.w)); break;
  605. case IMAGE_R10G10B10A2: {(*(UInt*)data)=Mid(RoundPos(color.x*0x3FF), 0, 0x3FF)|(Mid(RoundPos(color.y*0x3FF), 0, 0x3FF)<<10)|(Mid(RoundPos(color.z*0x3FF), 0, 0x3FF)<<20)|(Mid(RoundPos(color.w*3), 0, 3)<<30);} break;
  606. }
  607. }
  608. static void SetColorF(Byte *data, IMAGE_TYPE type, IMAGE_TYPE hw_type, C Vec4 &color)
  609. {
  610. if(type==hw_type)normal: return SetColorF(data, hw_type, color); // first check if types are the same, the most common case
  611. Vec4 c; switch(type) // however if we want 'type' but we've got 'hw_type' then we have to adjust the color we're going to set. This will prevent setting different R G B values for type=IMAGE_L8 when hw_type=IMAGE_R8G8B8A8
  612. {
  613. case IMAGE_R8G8B8:
  614. case IMAGE_F16_3 :
  615. case IMAGE_F32_3 : c.set(color.x, color.y, color.z, 1); break;
  616. case IMAGE_R8G8 :
  617. case IMAGE_F16_2:
  618. case IMAGE_F32_2: c.set(color.x, color.y, 0, 1); break;
  619. case IMAGE_R8 :
  620. case IMAGE_I8 :
  621. case IMAGE_I16:
  622. case IMAGE_I24:
  623. case IMAGE_I32:
  624. case IMAGE_F16:
  625. case IMAGE_F32: c.set(color.x, 0, 0, 1); break;
  626. case IMAGE_A8 : c.set(0, 0, 0, color.w); break;
  627. case IMAGE_L8 : {Flt l=color.xyz.max(); c.set(l, l, l, 1);} break;
  628. case IMAGE_L8A8: {Flt l=color.xyz.max(); c.set(l, l, l, color.w);} break;
  629. default: goto normal;
  630. }
  631. SetColorF(data, hw_type, c);
  632. }
  633. void Image::colorF(Int x, Int y, C Vec4 &color)
  634. {
  635. if(InRange(x, lw()) && InRange(y, lh())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  636. SetColorF(data() + x*bytePP() + y*pitch(), type(), hwType(), color);
  637. }
  638. void Image::color3DF(Int x, Int y, Int z, C Vec4 &color)
  639. {
  640. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  641. SetColorF(data() + x*bytePP() + y*pitch() + z*pitch2(), type(), hwType(), color);
  642. }
  643. /******************************************************************************/
  644. static inline void ApplyBlend(Vec4 &src, C Vec4 &color) {src=Blend(src, color);}
  645. void Image::blend(Int x, Int y, C Vec4 &color)
  646. {
  647. if(InRange(x, lw()) && InRange(y, lh())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  648. {
  649. Vec4 src;
  650. Byte *data=T.data() + x*bytePP() + y*pitch();
  651. switch(hwType())
  652. {
  653. case IMAGE_R8G8B8A8: {VecB4 &c=*(VecB4*)data; src.set(c.x/255.0f, c.y/255.0f, c.z/255.0f, c.w/255.0f); ApplyBlend(src, color); c.set(FltToByte(src.x), FltToByte(src.y), FltToByte(src.z), FltToByte(src.w));} break;
  654. case IMAGE_F32_4 : ApplyBlend(*(Vec4*)data, color); break;
  655. default :
  656. {
  657. src=colorF(x, y);
  658. ApplyBlend(src, color);
  659. SetColorF(data, type(), hwType(), src);
  660. }break;
  661. }
  662. }
  663. }
  664. static inline void ApplyMerge(Vec4 &src, C Vec4 &color) {src=PremultipliedBlend(src, color);}
  665. void Image::merge(Int x, Int y, C Vec4 &color)
  666. {
  667. if(InRange(x, lw()) && InRange(y, lh())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  668. {
  669. Vec4 src;
  670. Byte *data=T.data() + x*bytePP() + y*pitch();
  671. switch(hwType())
  672. {
  673. case IMAGE_R8G8B8A8: {VecB4 &c=*(VecB4*)data; src.set(c.x/255.0f, c.y/255.0f, c.z/255.0f, c.w/255.0f); ApplyMerge(src, color); c.set(FltToByte(src.x), FltToByte(src.y), FltToByte(src.z), FltToByte(src.w));} break;
  674. case IMAGE_F32_4 : ApplyMerge(*(Vec4*)data, color); break;
  675. default :
  676. {
  677. src=colorF(x, y);
  678. ApplyMerge(src, color);
  679. SetColorF(data, type(), hwType(), src);
  680. }break;
  681. }
  682. }
  683. }
  684. /******************************************************************************/
  685. Vec4 Image::colorF(Int x, Int y)C
  686. {
  687. if(InRange(x, lw()) && InRange(y, lh())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  688. {
  689. C Byte *data=T.data() + x*bytePP() + y*pitch();
  690. switch(hwType())
  691. {
  692. case IMAGE_F32 : return Vec4(*(Flt *)data, 0, 0, 1);
  693. case IMAGE_F32_2: return Vec4(*(Vec2*)data, 0, 1);
  694. case IMAGE_F32_3: return Vec4(*(Vec *)data, 1);
  695. case IMAGE_F32_4: return *(Vec4*)data ;
  696. case IMAGE_F16 : return Vec4(((Half*)data)[0], 0, 0, 1); break;
  697. case IMAGE_F16_2: return Vec4(((Half*)data)[0], ((Half*)data)[1], 0, 1); break;
  698. case IMAGE_F16_3: return Vec4(((Half*)data)[0], ((Half*)data)[1], ((Half*)data)[2], 1); break;
  699. case IMAGE_F16_4: return Vec4(((Half*)data)[0], ((Half*)data)[1], ((Half*)data)[2], ((Half*)data)[3]); break;
  700. case IMAGE_A8: return Vec4(0, 0, 0, Flt(*(U8*)data)/0x000000FFu);
  701. case IMAGE_L8: return Vec4(Vec( Flt(*(U8*)data)/0x000000FFu), 1);
  702. case IMAGE_I8: return Vec4(Vec( Flt(*(U8*)data)/0x000000FFu), 1);
  703. #if SUPPORT_DEPTH_TO_COLOR
  704. case IMAGE_D16: if(GL)return Vec4(Vec((*(U16*)data)/Flt(0x0000FFFFu)*2-1), 1); // !! else fall through no break on purpose !!
  705. #endif
  706. case IMAGE_I16: return Vec4(Vec((*(U16*)data)/Flt(0x0000FFFFu) ), 1);
  707. #if SUPPORT_DEPTH_TO_COLOR
  708. case IMAGE_D32 : return Vec4(Vec(GL ? (*(Flt*)data)*2-1 : *(Flt*)data), 1);
  709. //case IMAGE_D32I: if(GL)return Vec4(Vec((*(U32*)data)/Dbl(0xFFFFFFFFu)*2-1), 1); // !! else fall through no break on purpose !!
  710. #endif
  711. case IMAGE_I32 : return Vec4(Vec((*(U32*)data)/Dbl(0xFFFFFFFFu) ), 1); // Dbl required to get best precision
  712. #if SUPPORT_DEPTH_TO_COLOR
  713. case IMAGE_D24S8:
  714. case IMAGE_D24X8: if(GL)return Vec4(Vec((*(U16*)(data+1) | (data[3]<<16))/Flt(0x00FFFFFFu)*2-1), 1); // !! else fall through no break on purpose !!
  715. #endif
  716. case IMAGE_I24 : return Vec4(Vec((*(U16*) data | (data[2]<<16))/Flt(0x00FFFFFFu) ), 1); // here Dbl is not required, this was tested
  717. case IMAGE_L8A8: {VecB2 &c=*(VecB2*)data; Flt l=c.x/255.0f; return Vec4(l, l, l, c.y/255.0f);}
  718. case IMAGE_B8G8R8A8: {VecB4 &c=*(VecB4*)data; return Vec4(c.z/255.0f, c.y/255.0f, c.x/255.0f, c.w/255.0f);}
  719. case IMAGE_R8G8B8A8: {VecB4 &c=*(VecB4*)data; return Vec4(c.x/255.0f, c.y/255.0f, c.z/255.0f, c.w/255.0f);}
  720. case IMAGE_B8G8R8X8: {VecB4 &c=*(VecB4*)data; return Vec4(c.z/255.0f, c.y/255.0f, c.x/255.0f, 1);}
  721. case IMAGE_R8G8B8X8: {VecB4 &c=*(VecB4*)data; return Vec4(c.x/255.0f, c.y/255.0f, c.z/255.0f, 1);}
  722. case IMAGE_B8G8R8 : {VecB &c=*(VecB *)data; return Vec4(c.z/255.0f, c.y/255.0f, c.x/255.0f, 1);}
  723. case IMAGE_R8G8B8 : {VecB &c=*(VecB *)data; return Vec4(c.x/255.0f, c.y/255.0f, c.z/255.0f, 1);}
  724. case IMAGE_R8G8 : {VecB2 &c=*(VecB2*)data; return Vec4(c.x/255.0f, c.y/255.0f, 0, 1);}
  725. case IMAGE_R8 : {Byte c=*(Byte *)data; return Vec4(c /255.0f, 0, 0, 1);}
  726. case IMAGE_R8_SIGN : {Byte &c=*(Byte *)data; return Vec4(SByteToSFlt(c ), 0, 0 , 1 );}
  727. case IMAGE_R8G8_SIGN : {VecB2 &c=*(VecB2*)data; return Vec4(SByteToSFlt(c.x), SByteToSFlt(c.y), 0 , 1 );}
  728. case IMAGE_R8G8B8A8_SIGN: {VecB4 &c=*(VecB4*)data; return Vec4(SByteToSFlt(c.x), SByteToSFlt(c.y), SByteToSFlt(c.z), SByteToSFlt(c.w));}
  729. case IMAGE_R10G10B10A2: {UInt u=*(UInt*)data; return Vec4((u&0x3FF)/1023.0f, ((u>>10)&0x3FF)/1023.0f, ((u>>20)&0x3FF)/1023.0f, (u>>30)/3.0f);}
  730. case IMAGE_BC1 :
  731. case IMAGE_BC2 :
  732. case IMAGE_BC3 :
  733. case IMAGE_BC7 :
  734. case IMAGE_PVRTC1_2:
  735. case IMAGE_PVRTC1_4:
  736. case IMAGE_ETC1 :
  737. case IMAGE_ETC2 :
  738. case IMAGE_ETC2_A1 :
  739. case IMAGE_ETC2_A8 : return decompress(x, y).asVec4();
  740. }
  741. }
  742. return 0;
  743. }
  744. /******************************************************************************/
  745. Vec4 Image::color3DF(Int x, Int y, Int z)C
  746. {
  747. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld())) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  748. {
  749. C Byte *data=T.data() + x*bytePP() + y*pitch() + z*pitch2();
  750. switch(hwType())
  751. {
  752. case IMAGE_F32 : return Vec4(*(Flt *)data, 0, 0, 1);
  753. case IMAGE_F32_2: return Vec4(*(Vec2*)data, 0, 1);
  754. case IMAGE_F32_3: return Vec4(*(Vec *)data, 1);
  755. case IMAGE_F32_4: return *(Vec4*)data ;
  756. case IMAGE_F16 : return Vec4(((Half*)data)[0], 0, 0, 1); break;
  757. case IMAGE_F16_2: return Vec4(((Half*)data)[0], ((Half*)data)[1], 0, 1); break;
  758. case IMAGE_F16_3: return Vec4(((Half*)data)[0], ((Half*)data)[1], ((Half*)data)[2], 1); break;
  759. case IMAGE_F16_4: return Vec4(((Half*)data)[0], ((Half*)data)[1], ((Half*)data)[2], ((Half*)data)[3]); break;
  760. case IMAGE_A8: return Vec4(0, 0, 0, Flt(*(U8*)data)/0x000000FFu);
  761. case IMAGE_L8: return Vec4(Vec( Flt(*(U8*)data)/0x000000FFu), 1);
  762. case IMAGE_I8: return Vec4(Vec( Flt(*(U8*)data)/0x000000FFu), 1);
  763. #if SUPPORT_DEPTH_TO_COLOR
  764. case IMAGE_D16: if(GL)return Vec4(Vec((*(U16*)data)/Flt(0x0000FFFFu)*2-1), 1); // !! else fall through no break on purpose !!
  765. #endif
  766. case IMAGE_I16: return Vec4(Vec((*(U16*)data)/Flt(0x0000FFFFu) ), 1);
  767. #if SUPPORT_DEPTH_TO_COLOR
  768. case IMAGE_D32 : return Vec4(Vec(GL ? (*(Flt*)data)*2-1 : *(Flt*)data), 1);
  769. //case IMAGE_D32I: if(GL)return Vec4(Vec((*(U32*)data)/Dbl(0xFFFFFFFFu)*2-1), 1); // !! else fall through no break on purpose !!
  770. #endif
  771. case IMAGE_I32 : return Vec4(Vec((*(U32*)data)/Dbl(0xFFFFFFFFu) ), 1); // Dbl required to get best precision
  772. #if SUPPORT_DEPTH_TO_COLOR
  773. case IMAGE_D24S8:
  774. case IMAGE_D24X8: if(GL)return Vec4(Vec((*(U16*)(data+1) | (data[3]<<16))/Flt(0x00FFFFFFu)*2-1), 1); // !! else fall through no break on purpose !!
  775. #endif
  776. case IMAGE_I24 : return Vec4(Vec((*(U16*) data | (data[2]<<16))/Flt(0x00FFFFFFu) ), 1); // here Dbl is not required, this was tested
  777. case IMAGE_L8A8: {VecB2 &c=*(VecB2*)data; Flt l=c.x/255.0f; return Vec4(l, l, l, c.y/255.0f);}
  778. case IMAGE_B8G8R8A8: {VecB4 &c=*(VecB4*)data; return Vec4(c.z/255.0f, c.y/255.0f, c.x/255.0f, c.w/255.0f);}
  779. case IMAGE_R8G8B8A8: {VecB4 &c=*(VecB4*)data; return Vec4(c.x/255.0f, c.y/255.0f, c.z/255.0f, c.w/255.0f);}
  780. case IMAGE_B8G8R8X8: {VecB4 &c=*(VecB4*)data; return Vec4(c.z/255.0f, c.y/255.0f, c.x/255.0f, 1);}
  781. case IMAGE_R8G8B8X8: {VecB4 &c=*(VecB4*)data; return Vec4(c.x/255.0f, c.y/255.0f, c.z/255.0f, 1);}
  782. case IMAGE_B8G8R8 : {VecB &c=*(VecB *)data; return Vec4(c.z/255.0f, c.y/255.0f, c.x/255.0f, 1);}
  783. case IMAGE_R8G8B8 : {VecB &c=*(VecB *)data; return Vec4(c.x/255.0f, c.y/255.0f, c.z/255.0f, 1);}
  784. case IMAGE_R8G8 : {VecB2 &c=*(VecB2*)data; return Vec4(c.x/255.0f, c.y/255.0f, 0, 1);}
  785. case IMAGE_R8 : {Byte c=*(Byte *)data; return Vec4(c /255.0f, 0, 0, 1);}
  786. case IMAGE_R8_SIGN : {Byte &c=*(Byte *)data; return Vec4(SByteToSFlt(c ), 0, 0 , 1 );}
  787. case IMAGE_R8G8_SIGN : {VecB2 &c=*(VecB2*)data; return Vec4(SByteToSFlt(c.x), SByteToSFlt(c.y), 0 , 1 );}
  788. case IMAGE_R8G8B8A8_SIGN: {VecB4 &c=*(VecB4*)data; return Vec4(SByteToSFlt(c.x), SByteToSFlt(c.y), SByteToSFlt(c.z), SByteToSFlt(c.w));}
  789. case IMAGE_R10G10B10A2: {UInt u=*(UInt*)data; return Vec4((u&0x3FF)/1023.0f, ((u>>10)&0x3FF)/1023.0f, ((u>>20)&0x3FF)/1023.0f, (u>>30)/3.0f);}
  790. case IMAGE_BC1 :
  791. case IMAGE_BC2 :
  792. case IMAGE_BC3 :
  793. case IMAGE_BC7 :
  794. case IMAGE_PVRTC1_2:
  795. case IMAGE_PVRTC1_4:
  796. case IMAGE_ETC1 :
  797. case IMAGE_ETC2 :
  798. case IMAGE_ETC2_A1 :
  799. case IMAGE_ETC2_A8 : return decompress3D(x, y, z).asVec4();
  800. }
  801. }
  802. return 0;
  803. }
  804. /******************************************************************************/
  805. // LINEAR
  806. /******************************************************************************/
  807. Flt Image::pixelFLinear(Flt x, Flt y, Bool clamp)C
  808. {
  809. if(lw() && lh())
  810. {
  811. Int xo[2]; xo[0]=Floor(x); x-=xo[0];
  812. Int yo[2]; yo[0]=Floor(y); y-=yo[0];
  813. if(clamp)
  814. {
  815. xo[1]=xo[0]+1; if(xo[1]<0)xo[0]=xo[1]=0;else if(xo[0]>=lw())xo[0]=xo[1]=lw()-1;else if(xo[0]<0)xo[0]=0;else if(xo[1]>=lw())xo[1]=lw()-1;
  816. yo[1]=yo[0]+1; if(yo[1]<0)yo[0]=yo[1]=0;else if(yo[0]>=lh())yo[0]=yo[1]=lh()-1;else if(yo[0]<0)yo[0]=0;else if(yo[1]>=lh())yo[1]=lh()-1;
  817. }else
  818. {
  819. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw();
  820. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh();
  821. }
  822. Flt p[2][2]; gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  823. return p[0][0]*(1-x)*(1-y)
  824. +p[0][1]*( x)*(1-y)
  825. +p[1][0]*(1-x)*( y)
  826. +p[1][1]*( x)*( y);
  827. }
  828. return 0;
  829. }
  830. /******************************************************************************/
  831. Flt Image::pixel3DFLinear(Flt x, Flt y, Flt z, Bool clamp)C
  832. {
  833. if(lw() && lh() && ld())
  834. {
  835. Int xo[2]; xo[0]=Floor(x); x-=xo[0];
  836. Int yo[2]; yo[0]=Floor(y); y-=yo[0];
  837. Int zo[2]; zo[0]=Floor(z); z-=zo[0];
  838. if(clamp)
  839. {
  840. xo[1]=xo[0]+1; if(xo[1]<0)xo[0]=xo[1]=0;else if(xo[0]>=lw())xo[0]=xo[1]=lw()-1;else if(xo[0]<0)xo[0]=0;else if(xo[1]>=lw())xo[1]=lw()-1;
  841. yo[1]=yo[0]+1; if(yo[1]<0)yo[0]=yo[1]=0;else if(yo[0]>=lh())yo[0]=yo[1]=lh()-1;else if(yo[0]<0)yo[0]=0;else if(yo[1]>=lh())yo[1]=lh()-1;
  842. zo[1]=zo[0]+1; if(zo[1]<0)zo[0]=zo[1]=0;else if(zo[0]>=ld())zo[0]=zo[1]=ld()-1;else if(zo[0]<0)zo[0]=0;else if(zo[1]>=ld())zo[1]=ld()-1;
  843. }else
  844. {
  845. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw();
  846. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh();
  847. zo[0]=Mod(zo[0], ld()); zo[1]=(zo[0]+1)%ld();
  848. }
  849. Flt p[2][2][2]; gather(&p[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  850. return p[0][0][0]*(1-x)*(1-y)*(1-z)
  851. +p[0][0][1]*( x)*(1-y)*(1-z)
  852. +p[0][1][0]*(1-x)*( y)*(1-z)
  853. +p[0][1][1]*( x)*( y)*(1-z)
  854. +p[1][0][0]*(1-x)*(1-y)*( z)
  855. +p[1][0][1]*( x)*(1-y)*( z)
  856. +p[1][1][0]*(1-x)*( y)*( z)
  857. +p[1][1][1]*( x)*( y)*( z);
  858. }
  859. return 0;
  860. }
  861. /******************************************************************************/
  862. Vec4 Image::colorFLinear(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  863. {
  864. if(lw() && lh())
  865. {
  866. Int xo[2]; xo[0]=Floor(x); x-=xo[0];
  867. Int yo[2]; yo[0]=Floor(y); y-=yo[0];
  868. if(clamp)
  869. {
  870. xo[1]=xo[0]+1; if(xo[1]<0)xo[0]=xo[1]=0;else if(xo[0]>=lw())xo[0]=xo[1]=lw()-1;else if(xo[0]<0)xo[0]=0;else if(xo[1]>=lw())xo[1]=lw()-1;
  871. yo[1]=yo[0]+1; if(yo[1]<0)yo[0]=yo[1]=0;else if(yo[0]>=lh())yo[0]=yo[1]=lh()-1;else if(yo[0]<0)yo[0]=0;else if(yo[1]>=lh())yo[1]=lh()-1;
  872. }else
  873. {
  874. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw();
  875. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh();
  876. }
  877. Vec4 c[2][2]; gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  878. if(alpha_weight)
  879. {
  880. Vec rgb =0;
  881. Vec4 color=0;
  882. Add(color, rgb, c[0][0], (1-x)*(1-y), alpha_weight);
  883. Add(color, rgb, c[0][1], ( x)*(1-y), alpha_weight);
  884. Add(color, rgb, c[1][0], (1-x)*( y), alpha_weight);
  885. Add(color, rgb, c[1][1], ( x)*( y), alpha_weight);
  886. Normalize(color, rgb, alpha_weight, highPrecision());
  887. return color;
  888. }else
  889. return c[0][0]*(1-x)*(1-y)
  890. +c[0][1]*( x)*(1-y)
  891. +c[1][0]*(1-x)*( y)
  892. +c[1][1]*( x)*( y);
  893. }
  894. return 0;
  895. }
  896. Vec4 Image::colorFLinearTTNF32_4(Flt x, Flt y, Bool clamp)C // !! this assumes that image is already locked, exists and is of F32_4 type
  897. {
  898. Int xo[2]; xo[0]=Floor(x); x-=xo[0];
  899. Int yo[2]; yo[0]=Floor(y); y-=yo[0];
  900. if(clamp)
  901. {
  902. xo[1]=xo[0]+1; if(xo[1]<0)xo[0]=xo[1]=0;else if(xo[0]>=lw())xo[0]=xo[1]=lw()-1;else if(xo[0]<0)xo[0]=0;else if(xo[1]>=lw())xo[1]=lw()-1;
  903. yo[1]=yo[0]+1; if(yo[1]<0)yo[0]=yo[1]=0;else if(yo[0]>=lh())yo[0]=yo[1]=lh()-1;else if(yo[0]<0)yo[0]=0;else if(yo[1]>=lh())yo[1]=lh()-1;
  904. }else
  905. {
  906. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw();
  907. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh();
  908. }
  909. C Vec4 &c00=pixF4(xo[0], yo[0]),
  910. &c01=pixF4(xo[1], yo[0]),
  911. &c10=pixF4(xo[0], yo[1]),
  912. &c11=pixF4(xo[1], yo[1]);
  913. Vec4 color=0;
  914. if(c00.w>0 || c01.w>0 || c10.w>0 || c11.w>0) // we're only interested in interpolation if there will be any alpha
  915. {
  916. Vec rgb=0;
  917. Add(color, rgb, c00, (1-x)*(1-y), true);
  918. Add(color, rgb, c01, ( x)*(1-y), true);
  919. Add(color, rgb, c10, (1-x)*( y), true);
  920. Add(color, rgb, c11, ( x)*( y), true);
  921. Normalize(color, rgb, true, true);
  922. }
  923. return color;
  924. }
  925. /******************************************************************************/
  926. Vec4 Image::color3DFLinear(Flt x, Flt y, Flt z, Bool clamp, Bool alpha_weight)C
  927. {
  928. if(lw() && lh() && ld())
  929. {
  930. Int xo[2]; xo[0]=Floor(x); x-=xo[0];
  931. Int yo[2]; yo[0]=Floor(y); y-=yo[0];
  932. Int zo[2]; zo[0]=Floor(z); z-=zo[0];
  933. if(clamp)
  934. {
  935. xo[1]=xo[0]+1; if(xo[1]<0)xo[0]=xo[1]=0;else if(xo[0]>=lw())xo[0]=xo[1]=lw()-1;else if(xo[0]<0)xo[0]=0;else if(xo[1]>=lw())xo[1]=lw()-1;
  936. yo[1]=yo[0]+1; if(yo[1]<0)yo[0]=yo[1]=0;else if(yo[0]>=lh())yo[0]=yo[1]=lh()-1;else if(yo[0]<0)yo[0]=0;else if(yo[1]>=lh())yo[1]=lh()-1;
  937. zo[1]=zo[0]+1; if(zo[1]<0)zo[0]=zo[1]=0;else if(zo[0]>=ld())zo[0]=zo[1]=ld()-1;else if(zo[0]<0)zo[0]=0;else if(zo[1]>=ld())zo[1]=ld()-1;
  938. }else
  939. {
  940. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw();
  941. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh();
  942. zo[0]=Mod(zo[0], ld()); zo[1]=(zo[0]+1)%ld();
  943. }
  944. Vec4 c[2][2][2]; gather(&c[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  945. if(alpha_weight)
  946. {
  947. Vec rgb =0;
  948. Vec4 color=0;
  949. Add(color, rgb, c[0][0][0], (1-x)*(1-y)*(1-z), alpha_weight);
  950. Add(color, rgb, c[0][0][1], ( x)*(1-y)*(1-z), alpha_weight);
  951. Add(color, rgb, c[0][1][0], (1-x)*( y)*(1-z), alpha_weight);
  952. Add(color, rgb, c[0][1][1], ( x)*( y)*(1-z), alpha_weight);
  953. Add(color, rgb, c[1][0][0], (1-x)*(1-y)*( z), alpha_weight);
  954. Add(color, rgb, c[1][0][1], ( x)*(1-y)*( z), alpha_weight);
  955. Add(color, rgb, c[1][1][0], (1-x)*( y)*( z), alpha_weight);
  956. Add(color, rgb, c[1][1][1], ( x)*( y)*( z), alpha_weight);
  957. Normalize(color, rgb, alpha_weight, highPrecision());
  958. return color;
  959. }else
  960. return c[0][0][0]*(1-x)*(1-y)*(1-z)
  961. +c[0][0][1]*( x)*(1-y)*(1-z)
  962. +c[0][1][0]*(1-x)*( y)*(1-z)
  963. +c[0][1][1]*( x)*( y)*(1-z)
  964. +c[1][0][0]*(1-x)*(1-y)*( z)
  965. +c[1][0][1]*( x)*(1-y)*( z)
  966. +c[1][1][0]*(1-x)*( y)*( z)
  967. +c[1][1][1]*( x)*( y)*( z);
  968. }
  969. return 0;
  970. }
  971. /******************************************************************************/
  972. // CUBIC FAST
  973. /******************************************************************************/
  974. Flt Image::pixelFCubicFast(Flt x, Flt y, Bool clamp)C
  975. {
  976. if(lw() && lh())
  977. {
  978. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  979. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  980. if(clamp)
  981. {
  982. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  983. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  984. }else
  985. {
  986. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  987. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  988. }
  989. Flt p[4][4]; gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  990. Flt x0w=Sqr(x+1), x1w=Sqr(x), x2w=Sqr(x-1), x3w=Sqr(x-2),
  991. y0w=Sqr(y+1), y1w=Sqr(y), y2w=Sqr(y-1), y3w=Sqr(y-2),
  992. v=0, weight=0, w;
  993. w=x0w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[0][0]*w; weight+=w;}
  994. w=x1w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[0][1]*w; weight+=w;}
  995. w=x2w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[0][2]*w; weight+=w;}
  996. w=x3w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[0][3]*w; weight+=w;}
  997. w=x0w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[1][0]*w; weight+=w;}
  998. w=x1w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[1][1]*w; weight+=w;}
  999. w=x2w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[1][2]*w; weight+=w;}
  1000. w=x3w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[1][3]*w; weight+=w;}
  1001. w=x0w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[2][0]*w; weight+=w;}
  1002. w=x1w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[2][1]*w; weight+=w;}
  1003. w=x2w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[2][2]*w; weight+=w;}
  1004. w=x3w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[2][3]*w; weight+=w;}
  1005. w=x0w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[3][0]*w; weight+=w;}
  1006. w=x1w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[3][1]*w; weight+=w;}
  1007. w=x2w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[3][2]*w; weight+=w;}
  1008. w=x3w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); v+=p[3][3]*w; weight+=w;}
  1009. return v/weight;
  1010. }
  1011. return 0;
  1012. }
  1013. Flt Image::pixelFCubicFastSmooth(Flt x, Flt y, Bool clamp)C
  1014. {
  1015. if(lw() && lh())
  1016. {
  1017. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1018. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1019. if(clamp)
  1020. {
  1021. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1022. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1023. }else
  1024. {
  1025. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1026. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1027. }
  1028. Flt p[4][4]; gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1029. Flt x0w=Sqr(x+1), x1w=Sqr(x), x2w=Sqr(x-1), x3w=Sqr(x-2),
  1030. y0w=Sqr(y+1), y1w=Sqr(y), y2w=Sqr(y-1), y3w=Sqr(y-2),
  1031. v=0, weight=0, w;
  1032. w=x0w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[0][0]*w; weight+=w;}
  1033. w=x1w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[0][1]*w; weight+=w;}
  1034. w=x2w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[0][2]*w; weight+=w;}
  1035. w=x3w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[0][3]*w; weight+=w;}
  1036. w=x0w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[1][0]*w; weight+=w;}
  1037. w=x1w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[1][1]*w; weight+=w;}
  1038. w=x2w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[1][2]*w; weight+=w;}
  1039. w=x3w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[1][3]*w; weight+=w;}
  1040. w=x0w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[2][0]*w; weight+=w;}
  1041. w=x1w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[2][1]*w; weight+=w;}
  1042. w=x2w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[2][2]*w; weight+=w;}
  1043. w=x3w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[2][3]*w; weight+=w;}
  1044. w=x0w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[3][0]*w; weight+=w;}
  1045. w=x1w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[3][1]*w; weight+=w;}
  1046. w=x2w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[3][2]*w; weight+=w;}
  1047. w=x3w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); v+=p[3][3]*w; weight+=w;}
  1048. return v/weight;
  1049. }
  1050. return 0;
  1051. }
  1052. Flt Image::pixelFCubicFastSharp(Flt x, Flt y, Bool clamp)C
  1053. {
  1054. if(lw() && lh())
  1055. {
  1056. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1057. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1058. if(clamp)
  1059. {
  1060. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1061. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1062. }else
  1063. {
  1064. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1065. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1066. }
  1067. Flt p[4][4]; gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1068. Flt x0w=Sqr(x+1), x1w=Sqr(x), x2w=Sqr(x-1), x3w=Sqr(x-2),
  1069. y0w=Sqr(y+1), y1w=Sqr(y), y2w=Sqr(y-1), y3w=Sqr(y-2),
  1070. v=0, weight=0, w;
  1071. w=x0w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[0][0]*w; weight+=w;}
  1072. w=x1w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[0][1]*w; weight+=w;}
  1073. w=x2w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[0][2]*w; weight+=w;}
  1074. w=x3w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[0][3]*w; weight+=w;}
  1075. w=x0w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[1][0]*w; weight+=w;}
  1076. w=x1w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[1][1]*w; weight+=w;}
  1077. w=x2w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[1][2]*w; weight+=w;}
  1078. w=x3w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[1][3]*w; weight+=w;}
  1079. w=x0w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[2][0]*w; weight+=w;}
  1080. w=x1w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[2][1]*w; weight+=w;}
  1081. w=x2w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[2][2]*w; weight+=w;}
  1082. w=x3w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[2][3]*w; weight+=w;}
  1083. w=x0w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[3][0]*w; weight+=w;}
  1084. w=x1w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[3][1]*w; weight+=w;}
  1085. w=x2w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[3][2]*w; weight+=w;}
  1086. w=x3w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); v+=p[3][3]*w; weight+=w;}
  1087. return v/weight;
  1088. }
  1089. return 0;
  1090. }
  1091. /******************************************************************************/
  1092. Vec4 Image::colorFCubicFast(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  1093. {
  1094. if(lw() && lh())
  1095. {
  1096. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1097. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1098. if(clamp)
  1099. {
  1100. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1101. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1102. }else
  1103. {
  1104. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1105. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1106. }
  1107. Vec4 c[4][4]; gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1108. Vec rgb =0;
  1109. Vec4 color =0;
  1110. Flt weight=0, w,
  1111. x0w=Sqr(x+1), x1w=Sqr(x), x2w=Sqr(x-1), x3w=Sqr(x-2),
  1112. y0w=Sqr(y+1), y1w=Sqr(y), y2w=Sqr(y-1), y3w=Sqr(y-2);
  1113. w=x0w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[0][0], w, alpha_weight); weight+=w;}
  1114. w=x1w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[0][1], w, alpha_weight); weight+=w;}
  1115. w=x2w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[0][2], w, alpha_weight); weight+=w;}
  1116. w=x3w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[0][3], w, alpha_weight); weight+=w;}
  1117. w=x0w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[1][0], w, alpha_weight); weight+=w;}
  1118. w=x1w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[1][1], w, alpha_weight); weight+=w;}
  1119. w=x2w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[1][2], w, alpha_weight); weight+=w;}
  1120. w=x3w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[1][3], w, alpha_weight); weight+=w;}
  1121. w=x0w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[2][0], w, alpha_weight); weight+=w;}
  1122. w=x1w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[2][1], w, alpha_weight); weight+=w;}
  1123. w=x2w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[2][2], w, alpha_weight); weight+=w;}
  1124. w=x3w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[2][3], w, alpha_weight); weight+=w;}
  1125. w=x0w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[3][0], w, alpha_weight); weight+=w;}
  1126. w=x1w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[3][1], w, alpha_weight); weight+=w;}
  1127. w=x2w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[3][2], w, alpha_weight); weight+=w;}
  1128. w=x3w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFast2(w); Add(color, rgb, c[3][3], w, alpha_weight); weight+=w;}
  1129. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1130. return color;
  1131. }
  1132. return 0;
  1133. }
  1134. Vec4 Image::colorFCubicFastSmooth(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  1135. {
  1136. if(lw() && lh())
  1137. {
  1138. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1139. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1140. if(clamp)
  1141. {
  1142. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1143. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1144. }else
  1145. {
  1146. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1147. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1148. }
  1149. Vec4 c[4][4]; gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1150. Vec rgb =0;
  1151. Vec4 color =0;
  1152. Flt weight=0, w,
  1153. x0w=Sqr(x+1), x1w=Sqr(x), x2w=Sqr(x-1), x3w=Sqr(x-2),
  1154. y0w=Sqr(y+1), y1w=Sqr(y), y2w=Sqr(y-1), y3w=Sqr(y-2);
  1155. w=x0w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[0][0], w, alpha_weight); weight+=w;}
  1156. w=x1w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[0][1], w, alpha_weight); weight+=w;}
  1157. w=x2w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[0][2], w, alpha_weight); weight+=w;}
  1158. w=x3w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[0][3], w, alpha_weight); weight+=w;}
  1159. w=x0w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[1][0], w, alpha_weight); weight+=w;}
  1160. w=x1w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[1][1], w, alpha_weight); weight+=w;}
  1161. w=x2w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[1][2], w, alpha_weight); weight+=w;}
  1162. w=x3w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[1][3], w, alpha_weight); weight+=w;}
  1163. w=x0w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[2][0], w, alpha_weight); weight+=w;}
  1164. w=x1w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[2][1], w, alpha_weight); weight+=w;}
  1165. w=x2w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[2][2], w, alpha_weight); weight+=w;}
  1166. w=x3w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[2][3], w, alpha_weight); weight+=w;}
  1167. w=x0w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[3][0], w, alpha_weight); weight+=w;}
  1168. w=x1w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[3][1], w, alpha_weight); weight+=w;}
  1169. w=x2w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[3][2], w, alpha_weight); weight+=w;}
  1170. w=x3w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSmooth2(w); Add(color, rgb, c[3][3], w, alpha_weight); weight+=w;}
  1171. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1172. return color;
  1173. }
  1174. return 0;
  1175. }
  1176. Vec4 Image::colorFCubicFastSharp(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  1177. {
  1178. if(lw() && lh())
  1179. {
  1180. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1181. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1182. if(clamp)
  1183. {
  1184. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1185. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1186. }else
  1187. {
  1188. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1189. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1190. }
  1191. Vec4 c[4][4]; gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1192. Vec rgb =0;
  1193. Vec4 color =0;
  1194. Flt weight=0, w,
  1195. x0w=Sqr(x+1), x1w=Sqr(x), x2w=Sqr(x-1), x3w=Sqr(x-2),
  1196. y0w=Sqr(y+1), y1w=Sqr(y), y2w=Sqr(y-1), y3w=Sqr(y-2);
  1197. w=x0w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[0][0], w, alpha_weight); weight+=w;}
  1198. w=x1w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[0][1], w, alpha_weight); weight+=w;}
  1199. w=x2w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[0][2], w, alpha_weight); weight+=w;}
  1200. w=x3w+y0w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[0][3], w, alpha_weight); weight+=w;}
  1201. w=x0w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[1][0], w, alpha_weight); weight+=w;}
  1202. w=x1w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[1][1], w, alpha_weight); weight+=w;}
  1203. w=x2w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[1][2], w, alpha_weight); weight+=w;}
  1204. w=x3w+y1w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[1][3], w, alpha_weight); weight+=w;}
  1205. w=x0w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[2][0], w, alpha_weight); weight+=w;}
  1206. w=x1w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[2][1], w, alpha_weight); weight+=w;}
  1207. w=x2w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[2][2], w, alpha_weight); weight+=w;}
  1208. w=x3w+y2w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[2][3], w, alpha_weight); weight+=w;}
  1209. w=x0w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[3][0], w, alpha_weight); weight+=w;}
  1210. w=x1w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[3][1], w, alpha_weight); weight+=w;}
  1211. w=x2w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[3][2], w, alpha_weight); weight+=w;}
  1212. w=x3w+y3w; if(w<Sqr(CUBIC_FAST_RANGE)){w=CubicFastSharp2(w); Add(color, rgb, c[3][3], w, alpha_weight); weight+=w;}
  1213. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1214. return color;
  1215. }
  1216. return 0;
  1217. }
  1218. /******************************************************************************/
  1219. Flt Image::pixel3DFCubicFast(Flt x, Flt y, Flt z, Bool clamp)C
  1220. {
  1221. if(lw() && lh() && ld())
  1222. {
  1223. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], zo[CUBIC_FAST_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1224. Flt xw[CUBIC_FAST_SAMPLES*2], yw[CUBIC_FAST_SAMPLES*2], zw[CUBIC_FAST_SAMPLES*2];
  1225. Flt p [CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  1226. REPA(xo)
  1227. {
  1228. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1229. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1230. zo[i]=zi-CUBIC_FAST_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1231. if(clamp)
  1232. {
  1233. Clamp(xo[i], 0, lw()-1);
  1234. Clamp(yo[i], 0, lh()-1);
  1235. Clamp(zo[i], 0, ld()-1);
  1236. }else
  1237. {
  1238. xo[i]=Mod(xo[i], lw());
  1239. yo[i]=Mod(yo[i], lh());
  1240. zo[i]=Mod(zo[i], ld());
  1241. }
  1242. }
  1243. gather(&p[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1244. Flt weight=0, v=0;
  1245. REPAD(z, zo)
  1246. REPAD(y, yo)
  1247. REPAD(x, xo)
  1248. {
  1249. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_FAST_RANGE))
  1250. {
  1251. w=CubicFast2(w); v+=p[z][y][x]*w; weight+=w;
  1252. }
  1253. }
  1254. return v/weight;
  1255. }
  1256. return 0;
  1257. }
  1258. Flt Image::pixel3DFCubicFastSmooth(Flt x, Flt y, Flt z, Bool clamp)C
  1259. {
  1260. if(lw() && lh() && ld())
  1261. {
  1262. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], zo[CUBIC_FAST_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1263. Flt xw[CUBIC_FAST_SAMPLES*2], yw[CUBIC_FAST_SAMPLES*2], zw[CUBIC_FAST_SAMPLES*2];
  1264. Flt p [CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  1265. REPA(xo)
  1266. {
  1267. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1268. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1269. zo[i]=zi-CUBIC_FAST_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1270. if(clamp)
  1271. {
  1272. Clamp(xo[i], 0, lw()-1);
  1273. Clamp(yo[i], 0, lh()-1);
  1274. Clamp(zo[i], 0, ld()-1);
  1275. }else
  1276. {
  1277. xo[i]=Mod(xo[i], lw());
  1278. yo[i]=Mod(yo[i], lh());
  1279. zo[i]=Mod(zo[i], ld());
  1280. }
  1281. }
  1282. gather(&p[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1283. Flt weight=0, v=0;
  1284. REPAD(z, zo)
  1285. REPAD(y, yo)
  1286. REPAD(x, xo)
  1287. {
  1288. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_FAST_RANGE))
  1289. {
  1290. w=CubicFastSmooth2(w); v+=p[z][y][x]*w; weight+=w;
  1291. }
  1292. }
  1293. return v/weight;
  1294. }
  1295. return 0;
  1296. }
  1297. Flt Image::pixel3DFCubicFastSharp(Flt x, Flt y, Flt z, Bool clamp)C
  1298. {
  1299. if(lw() && lh() && ld())
  1300. {
  1301. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], zo[CUBIC_FAST_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1302. Flt xw[CUBIC_FAST_SAMPLES*2], yw[CUBIC_FAST_SAMPLES*2], zw[CUBIC_FAST_SAMPLES*2];
  1303. Flt p [CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  1304. REPA(xo)
  1305. {
  1306. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1307. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1308. zo[i]=zi-CUBIC_FAST_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1309. if(clamp)
  1310. {
  1311. Clamp(xo[i], 0, lw()-1);
  1312. Clamp(yo[i], 0, lh()-1);
  1313. Clamp(zo[i], 0, ld()-1);
  1314. }else
  1315. {
  1316. xo[i]=Mod(xo[i], lw());
  1317. yo[i]=Mod(yo[i], lh());
  1318. zo[i]=Mod(zo[i], ld());
  1319. }
  1320. }
  1321. gather(&p[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1322. Flt weight=0, v=0;
  1323. REPAD(z, zo)
  1324. REPAD(y, yo)
  1325. REPAD(x, xo)
  1326. {
  1327. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_FAST_RANGE))
  1328. {
  1329. w=CubicFastSharp2(w); v+=p[z][y][x]*w; weight+=w;
  1330. }
  1331. }
  1332. return v/weight;
  1333. }
  1334. return 0;
  1335. }
  1336. /******************************************************************************/
  1337. Flt Image::pixelFCubic(Flt x, Flt y, Bool clamp)C
  1338. {
  1339. if(lw() && lh())
  1340. {
  1341. Int xo[CUBIC_MED_SAMPLES*2], yo[CUBIC_MED_SAMPLES*2], xi=Floor(x), yi=Floor(y);
  1342. Flt xw[CUBIC_MED_SAMPLES*2], yw[CUBIC_MED_SAMPLES*2];
  1343. Flt p [CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2];
  1344. REPA(xo)
  1345. {
  1346. xo[i]=xi-CUBIC_MED_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1347. yo[i]=yi-CUBIC_MED_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1348. if(clamp)
  1349. {
  1350. Clamp(xo[i], 0, lw()-1);
  1351. Clamp(yo[i], 0, lh()-1);
  1352. }else
  1353. {
  1354. xo[i]=Mod(xo[i], lw());
  1355. yo[i]=Mod(yo[i], lh());
  1356. }
  1357. }
  1358. gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1359. Flt weight=0, v=0;
  1360. REPAD(y, yo)
  1361. REPAD(x, xo)
  1362. {
  1363. Flt w=xw[x]+yw[y]; if(w<Sqr(CUBIC_MED_RANGE))
  1364. {
  1365. w=CubicMed2(w*Sqr(CUBIC_MED_SHARPNESS)); v+=p[y][x]*w; weight+=w;
  1366. }
  1367. }
  1368. return v/weight;
  1369. }
  1370. return 0;
  1371. }
  1372. Flt Image::pixelFCubicSharp(Flt x, Flt y, Bool clamp)C
  1373. {
  1374. if(lw() && lh())
  1375. {
  1376. Int xo[CUBIC_SHARP_SAMPLES*2], yo[CUBIC_SHARP_SAMPLES*2], xi=Floor(x), yi=Floor(y);
  1377. Flt xw[CUBIC_SHARP_SAMPLES*2], yw[CUBIC_SHARP_SAMPLES*2];
  1378. Flt p [CUBIC_SHARP_SAMPLES*2][CUBIC_SHARP_SAMPLES*2];
  1379. REPA(xo)
  1380. {
  1381. xo[i]=xi-CUBIC_SHARP_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1382. yo[i]=yi-CUBIC_SHARP_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1383. if(clamp)
  1384. {
  1385. Clamp(xo[i], 0, lw()-1);
  1386. Clamp(yo[i], 0, lh()-1);
  1387. }else
  1388. {
  1389. xo[i]=Mod(xo[i], lw());
  1390. yo[i]=Mod(yo[i], lh());
  1391. }
  1392. }
  1393. gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1394. Flt weight=0, v=0;
  1395. REPAD(y, yo)
  1396. REPAD(x, xo)
  1397. {
  1398. Flt w=xw[x]+yw[y]; if(w<Sqr(CUBIC_SHARP_RANGE))
  1399. {
  1400. w=CubicSharp2(w*Sqr(CUBIC_SHARP_SHARPNESS)); v+=p[y][x]*w; weight+=w;
  1401. }
  1402. }
  1403. return v/weight;
  1404. }
  1405. return 0;
  1406. }
  1407. Flt Image::pixel3DFCubic(Flt x, Flt y, Flt z, Bool clamp)C
  1408. {
  1409. if(lw() && lh() && ld())
  1410. {
  1411. Int xo[CUBIC_MED_SAMPLES*2], yo[CUBIC_MED_SAMPLES*2], zo[CUBIC_MED_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1412. Flt xw[CUBIC_MED_SAMPLES*2], yw[CUBIC_MED_SAMPLES*2], zw[CUBIC_MED_SAMPLES*2];
  1413. Flt p [CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2];
  1414. REPA(xo)
  1415. {
  1416. xo[i]=xi-CUBIC_MED_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1417. yo[i]=yi-CUBIC_MED_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1418. zo[i]=zi-CUBIC_MED_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1419. if(clamp)
  1420. {
  1421. Clamp(xo[i], 0, lw()-1);
  1422. Clamp(yo[i], 0, lh()-1);
  1423. Clamp(zo[i], 0, ld()-1);
  1424. }else
  1425. {
  1426. xo[i]=Mod(xo[i], lw());
  1427. yo[i]=Mod(yo[i], lh());
  1428. zo[i]=Mod(zo[i], ld());
  1429. }
  1430. }
  1431. gather(&p[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1432. Flt weight=0, v=0;
  1433. REPAD(z, zo)
  1434. REPAD(y, yo)
  1435. REPAD(x, xo)
  1436. {
  1437. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_MED_RANGE))
  1438. {
  1439. w=CubicMed2(w*Sqr(CUBIC_MED_SHARPNESS)); v+=p[z][y][x]*w; weight+=w;
  1440. }
  1441. }
  1442. return v/weight;
  1443. }
  1444. return 0;
  1445. }
  1446. Flt Image::pixel3DFCubicSharp(Flt x, Flt y, Flt z, Bool clamp)C
  1447. {
  1448. if(lw() && lh() && ld())
  1449. {
  1450. Int xo[CUBIC_SHARP_SAMPLES*2], yo[CUBIC_SHARP_SAMPLES*2], zo[CUBIC_SHARP_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1451. Flt xw[CUBIC_SHARP_SAMPLES*2], yw[CUBIC_SHARP_SAMPLES*2], zw[CUBIC_SHARP_SAMPLES*2];
  1452. Flt p [CUBIC_SHARP_SAMPLES*2][CUBIC_SHARP_SAMPLES*2][CUBIC_SHARP_SAMPLES*2];
  1453. REPA(xo)
  1454. {
  1455. xo[i]=xi-CUBIC_SHARP_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1456. yo[i]=yi-CUBIC_SHARP_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1457. zo[i]=zi-CUBIC_SHARP_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1458. if(clamp)
  1459. {
  1460. Clamp(xo[i], 0, lw()-1);
  1461. Clamp(yo[i], 0, lh()-1);
  1462. Clamp(zo[i], 0, ld()-1);
  1463. }else
  1464. {
  1465. xo[i]=Mod(xo[i], lw());
  1466. yo[i]=Mod(yo[i], lh());
  1467. zo[i]=Mod(zo[i], ld());
  1468. }
  1469. }
  1470. gather(&p[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1471. Flt weight=0, v=0;
  1472. REPAD(z, zo)
  1473. REPAD(y, yo)
  1474. REPAD(x, xo)
  1475. {
  1476. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_SHARP_RANGE))
  1477. {
  1478. w=CubicSharp2(w*Sqr(CUBIC_SHARP_SHARPNESS)); v+=p[z][y][x]*w; weight+=w;
  1479. }
  1480. }
  1481. return v/weight;
  1482. }
  1483. return 0;
  1484. }
  1485. /******************************************************************************/
  1486. Vec4 Image::colorFCubic(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  1487. {
  1488. if(lw() && lh())
  1489. {
  1490. Int xo[CUBIC_MED_SAMPLES*2], yo[CUBIC_MED_SAMPLES*2], xi=Floor(x), yi=Floor(y);
  1491. Flt xw[CUBIC_MED_SAMPLES*2], yw[CUBIC_MED_SAMPLES*2];
  1492. Vec4 c [CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2];
  1493. REPA(xo)
  1494. {
  1495. xo[i]=xi-CUBIC_MED_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1496. yo[i]=yi-CUBIC_MED_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1497. if(clamp)
  1498. {
  1499. Clamp(xo[i], 0, lw()-1);
  1500. Clamp(yo[i], 0, lh()-1);
  1501. }else
  1502. {
  1503. xo[i]=Mod(xo[i], lw());
  1504. yo[i]=Mod(yo[i], lh());
  1505. }
  1506. }
  1507. gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1508. Flt weight=0;
  1509. Vec rgb =0;
  1510. Vec4 color =0;
  1511. REPAD(y, yo)
  1512. REPAD(x, xo)
  1513. {
  1514. Flt w=xw[x]+yw[y]; if(w<Sqr(CUBIC_MED_RANGE))
  1515. {
  1516. w=CubicMed2(w*Sqr(CUBIC_MED_SHARPNESS)); Add(color, rgb, c[y][x], w, alpha_weight); weight+=w;
  1517. }
  1518. }
  1519. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1520. return color;
  1521. }
  1522. return 0;
  1523. }
  1524. Vec4 Image::colorFCubicSharp(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  1525. {
  1526. if(lw() && lh())
  1527. {
  1528. Int xo[CUBIC_SHARP_SAMPLES*2], yo[CUBIC_SHARP_SAMPLES*2], xi=Floor(x), yi=Floor(y);
  1529. Flt xw[CUBIC_SHARP_SAMPLES*2], yw[CUBIC_SHARP_SAMPLES*2];
  1530. Vec4 c [CUBIC_SHARP_SAMPLES*2][CUBIC_SHARP_SAMPLES*2];
  1531. REPA(xo)
  1532. {
  1533. xo[i]=xi-CUBIC_SHARP_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1534. yo[i]=yi-CUBIC_SHARP_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1535. if(clamp)
  1536. {
  1537. Clamp(xo[i], 0, lw()-1);
  1538. Clamp(yo[i], 0, lh()-1);
  1539. }else
  1540. {
  1541. xo[i]=Mod(xo[i], lw());
  1542. yo[i]=Mod(yo[i], lh());
  1543. }
  1544. }
  1545. gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1546. Flt weight=0;
  1547. Vec rgb =0;
  1548. Vec4 color =0;
  1549. REPAD(y, yo)
  1550. REPAD(x, xo)
  1551. {
  1552. Flt w=xw[x]+yw[y]; if(w<Sqr(CUBIC_SHARP_RANGE))
  1553. {
  1554. w=CubicSharp2(w*Sqr(CUBIC_SHARP_SHARPNESS)); Add(color, rgb, c[y][x], w, alpha_weight); weight+=w;
  1555. }
  1556. }
  1557. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1558. return color;
  1559. }
  1560. return 0;
  1561. }
  1562. Vec4 Image::color3DFCubic(Flt x, Flt y, Flt z, Bool clamp, Bool alpha_weight)C
  1563. {
  1564. if(lw() && lh() && ld())
  1565. {
  1566. Int xo[CUBIC_MED_SAMPLES*2], yo[CUBIC_MED_SAMPLES*2], zo[CUBIC_MED_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1567. Flt xw[CUBIC_MED_SAMPLES*2], yw[CUBIC_MED_SAMPLES*2], zw[CUBIC_MED_SAMPLES*2];
  1568. Vec4 c [CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2];
  1569. REPA(xo)
  1570. {
  1571. xo[i]=xi-CUBIC_MED_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1572. yo[i]=yi-CUBIC_MED_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1573. zo[i]=zi-CUBIC_MED_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1574. if(clamp)
  1575. {
  1576. Clamp(xo[i], 0, lw()-1);
  1577. Clamp(yo[i], 0, lh()-1);
  1578. Clamp(zo[i], 0, ld()-1);
  1579. }else
  1580. {
  1581. xo[i]=Mod(xo[i], lw());
  1582. yo[i]=Mod(yo[i], lh());
  1583. zo[i]=Mod(zo[i], ld());
  1584. }
  1585. }
  1586. gather(&c[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1587. Flt weight=0;
  1588. Vec rgb =0;
  1589. Vec4 color =0;
  1590. REPAD(z, zo)
  1591. REPAD(y, yo)
  1592. REPAD(x, xo)
  1593. {
  1594. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_MED_RANGE))
  1595. {
  1596. w=CubicMed2(w*Sqr(CUBIC_MED_SHARPNESS)); Add(color, rgb, c[z][y][x], w, alpha_weight); weight+=w;
  1597. }
  1598. }
  1599. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1600. return color;
  1601. }
  1602. return 0;
  1603. }
  1604. Vec4 Image::color3DFCubicSharp(Flt x, Flt y, Flt z, Bool clamp, Bool alpha_weight)C
  1605. {
  1606. if(lw() && lh() && ld())
  1607. {
  1608. Int xo[CUBIC_SHARP_SAMPLES*2], yo[CUBIC_SHARP_SAMPLES*2], zo[CUBIC_SHARP_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1609. Flt xw[CUBIC_SHARP_SAMPLES*2], yw[CUBIC_SHARP_SAMPLES*2], zw[CUBIC_SHARP_SAMPLES*2];
  1610. Vec4 c [CUBIC_SHARP_SAMPLES*2][CUBIC_SHARP_SAMPLES*2][CUBIC_SHARP_SAMPLES*2];
  1611. REPA(xo)
  1612. {
  1613. xo[i]=xi-CUBIC_SHARP_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1614. yo[i]=yi-CUBIC_SHARP_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1615. zo[i]=zi-CUBIC_SHARP_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1616. if(clamp)
  1617. {
  1618. Clamp(xo[i], 0, lw()-1);
  1619. Clamp(yo[i], 0, lh()-1);
  1620. Clamp(zo[i], 0, ld()-1);
  1621. }else
  1622. {
  1623. xo[i]=Mod(xo[i], lw());
  1624. yo[i]=Mod(yo[i], lh());
  1625. zo[i]=Mod(zo[i], ld());
  1626. }
  1627. }
  1628. gather(&c[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1629. Flt weight=0;
  1630. Vec rgb =0;
  1631. Vec4 color =0;
  1632. REPAD(z, zo)
  1633. REPAD(y, yo)
  1634. REPAD(x, xo)
  1635. {
  1636. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_SHARP_RANGE))
  1637. {
  1638. w=CubicSharp2(w*Sqr(CUBIC_SHARP_SHARPNESS)); Add(color, rgb, c[z][y][x], w, alpha_weight); weight+=w;
  1639. }
  1640. }
  1641. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1642. return color;
  1643. }
  1644. return 0;
  1645. }
  1646. Vec4 Image::color3DFCubicFast(Flt x, Flt y, Flt z, Bool clamp, Bool alpha_weight)C
  1647. {
  1648. if(lw() && lh() && ld())
  1649. {
  1650. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], zo[CUBIC_FAST_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1651. Flt xw[CUBIC_FAST_SAMPLES*2], yw[CUBIC_FAST_SAMPLES*2], zw[CUBIC_FAST_SAMPLES*2];
  1652. Vec4 c [CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  1653. REPA(xo)
  1654. {
  1655. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1656. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1657. zo[i]=zi-CUBIC_FAST_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1658. if(clamp)
  1659. {
  1660. Clamp(xo[i], 0, lw()-1);
  1661. Clamp(yo[i], 0, lh()-1);
  1662. Clamp(zo[i], 0, ld()-1);
  1663. }else
  1664. {
  1665. xo[i]=Mod(xo[i], lw());
  1666. yo[i]=Mod(yo[i], lh());
  1667. zo[i]=Mod(zo[i], ld());
  1668. }
  1669. }
  1670. gather(&c[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1671. Flt weight=0;
  1672. Vec rgb =0;
  1673. Vec4 color =0;
  1674. REPAD(z, zo)
  1675. REPAD(y, yo)
  1676. REPAD(x, xo)
  1677. {
  1678. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_FAST_RANGE))
  1679. {
  1680. w=CubicFast2(w); Add(color, rgb, c[z][y][x], w, alpha_weight); weight+=w;
  1681. }
  1682. }
  1683. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1684. return color;
  1685. }
  1686. return 0;
  1687. }
  1688. Vec4 Image::color3DFCubicFastSmooth(Flt x, Flt y, Flt z, Bool clamp, Bool alpha_weight)C
  1689. {
  1690. if(lw() && lh() && ld())
  1691. {
  1692. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], zo[CUBIC_FAST_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1693. Flt xw[CUBIC_FAST_SAMPLES*2], yw[CUBIC_FAST_SAMPLES*2], zw[CUBIC_FAST_SAMPLES*2];
  1694. Vec4 c [CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  1695. REPA(xo)
  1696. {
  1697. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1698. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1699. zo[i]=zi-CUBIC_FAST_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1700. if(clamp)
  1701. {
  1702. Clamp(xo[i], 0, lw()-1);
  1703. Clamp(yo[i], 0, lh()-1);
  1704. Clamp(zo[i], 0, ld()-1);
  1705. }else
  1706. {
  1707. xo[i]=Mod(xo[i], lw());
  1708. yo[i]=Mod(yo[i], lh());
  1709. zo[i]=Mod(zo[i], ld());
  1710. }
  1711. }
  1712. gather(&c[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1713. Flt weight=0;
  1714. Vec rgb =0;
  1715. Vec4 color =0;
  1716. REPAD(z, zo)
  1717. REPAD(y, yo)
  1718. REPAD(x, xo)
  1719. {
  1720. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_FAST_RANGE))
  1721. {
  1722. w=CubicFastSmooth2(w); Add(color, rgb, c[z][y][x], w, alpha_weight); weight+=w;
  1723. }
  1724. }
  1725. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1726. return color;
  1727. }
  1728. return 0;
  1729. }
  1730. Vec4 Image::color3DFCubicFastSharp(Flt x, Flt y, Flt z, Bool clamp, Bool alpha_weight)C
  1731. {
  1732. if(lw() && lh() && ld())
  1733. {
  1734. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], zo[CUBIC_FAST_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  1735. Flt xw[CUBIC_FAST_SAMPLES*2], yw[CUBIC_FAST_SAMPLES*2], zw[CUBIC_FAST_SAMPLES*2];
  1736. Vec4 c [CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  1737. REPA(xo)
  1738. {
  1739. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i; xw[i]=Sqr(x-xo[i]);
  1740. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(y-yo[i]);
  1741. zo[i]=zi-CUBIC_FAST_SAMPLES+1+i; zw[i]=Sqr(z-zo[i]);
  1742. if(clamp)
  1743. {
  1744. Clamp(xo[i], 0, lw()-1);
  1745. Clamp(yo[i], 0, lh()-1);
  1746. Clamp(zo[i], 0, ld()-1);
  1747. }else
  1748. {
  1749. xo[i]=Mod(xo[i], lw());
  1750. yo[i]=Mod(yo[i], lh());
  1751. zo[i]=Mod(zo[i], ld());
  1752. }
  1753. }
  1754. gather(&c[0][0][0], xo, Elms(xo), yo, Elms(yo), zo, Elms(zo)); // [z][y][x]
  1755. Flt weight=0;
  1756. Vec rgb =0;
  1757. Vec4 color =0;
  1758. REPAD(z, zo)
  1759. REPAD(y, yo)
  1760. REPAD(x, xo)
  1761. {
  1762. Flt w=xw[x]+yw[y]+zw[z]; if(w<Sqr(CUBIC_FAST_RANGE))
  1763. {
  1764. w=CubicFastSharp2(w); Add(color, rgb, c[z][y][x], w, alpha_weight); weight+=w;
  1765. }
  1766. }
  1767. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  1768. return color;
  1769. }
  1770. return 0;
  1771. }
  1772. /******************************************************************************/
  1773. // CUBIC ORTHO
  1774. /******************************************************************************
  1775. Flt Image::pixelFCubicOrtho(Flt x, Flt y, Bool clamp)C
  1776. {
  1777. if(lw() && lh())
  1778. {
  1779. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1780. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1781. if(clamp)
  1782. {
  1783. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1784. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1785. }else
  1786. {
  1787. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1788. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1789. }
  1790. Flt p[4][4]; gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1791. #if 0
  1792. return Lerp4(
  1793. Lerp4(p[0][0], p[0][1], p[0][2], p[0][3], x),
  1794. Lerp4(p[1][0], p[1][1], p[1][2], p[1][3], x),
  1795. Lerp4(p[2][0], p[2][1], p[2][2], p[2][3], x),
  1796. Lerp4(p[3][0], p[3][1], p[3][2], p[3][3], x), y);
  1797. #else // optimized
  1798. Vec4 xb; Lerp4Weights(xb, x);
  1799. return Lerp4(
  1800. p[0][0]*xb.x + p[0][1]*xb.y + p[0][2]*xb.z + p[0][3]*xb.w,
  1801. p[1][0]*xb.x + p[1][1]*xb.y + p[1][2]*xb.z + p[1][3]*xb.w,
  1802. p[2][0]*xb.x + p[2][1]*xb.y + p[2][2]*xb.z + p[2][3]*xb.w,
  1803. p[3][0]*xb.x + p[3][1]*xb.y + p[3][2]*xb.z + p[3][3]*xb.w, y);
  1804. #endif
  1805. }
  1806. return 0;
  1807. }
  1808. /******************************************************************************
  1809. Flt Image::pixel3DFCubicOrtho(Flt x, Flt y, Flt z, Bool clamp)C
  1810. {
  1811. if(lw() && lh() && ld())
  1812. {
  1813. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1814. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1815. Int zo[4]; zo[0]=Floor(z); z-=zo[0]; zo[0]--;
  1816. if(clamp)
  1817. {
  1818. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1819. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1820. zo[1]=Mid(zo[0]+1, 0, ld()-1); zo[2]=Mid(zo[0]+2, 0, ld()-1); zo[3]=Mid(zo[0]+3, 0, ld()-1); Clamp(zo[0], 0, ld()-1);
  1821. }else
  1822. {
  1823. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1824. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1825. zo[0]=Mod(zo[0], ld()); zo[1]=(zo[0]+1)%ld(); zo[2]=(zo[0]+2)%ld(); zo[3]=(zo[0]+3)%ld();
  1826. }
  1827. Flt p000=pixel3DF(xo[0], yo[0], zo[0]), p100=pixel3DF(xo[1], yo[0], zo[0]), p200=pixel3DF(xo[2], yo[0], zo[0]), p300=pixel3DF(xo[3], yo[0], zo[0]),
  1828. p010=pixel3DF(xo[0], yo[1], zo[0]), p110=pixel3DF(xo[1], yo[1], zo[0]), p210=pixel3DF(xo[2], yo[1], zo[0]), p310=pixel3DF(xo[3], yo[1], zo[0]),
  1829. p020=pixel3DF(xo[0], yo[2], zo[0]), p120=pixel3DF(xo[1], yo[2], zo[0]), p220=pixel3DF(xo[2], yo[2], zo[0]), p320=pixel3DF(xo[3], yo[2], zo[0]),
  1830. p030=pixel3DF(xo[0], yo[3], zo[0]), p130=pixel3DF(xo[1], yo[3], zo[0]), p230=pixel3DF(xo[2], yo[3], zo[0]), p330=pixel3DF(xo[3], yo[3], zo[0]),
  1831. p001=pixel3DF(xo[0], yo[0], zo[1]), p101=pixel3DF(xo[1], yo[0], zo[1]), p201=pixel3DF(xo[2], yo[0], zo[1]), p301=pixel3DF(xo[3], yo[0], zo[1]),
  1832. p011=pixel3DF(xo[0], yo[1], zo[1]), p111=pixel3DF(xo[1], yo[1], zo[1]), p211=pixel3DF(xo[2], yo[1], zo[1]), p311=pixel3DF(xo[3], yo[1], zo[1]),
  1833. p021=pixel3DF(xo[0], yo[2], zo[1]), p121=pixel3DF(xo[1], yo[2], zo[1]), p221=pixel3DF(xo[2], yo[2], zo[1]), p321=pixel3DF(xo[3], yo[2], zo[1]),
  1834. p031=pixel3DF(xo[0], yo[3], zo[1]), p131=pixel3DF(xo[1], yo[3], zo[1]), p231=pixel3DF(xo[2], yo[3], zo[1]), p331=pixel3DF(xo[3], yo[3], zo[1]),
  1835. p002=pixel3DF(xo[0], yo[0], zo[2]), p102=pixel3DF(xo[1], yo[0], zo[2]), p202=pixel3DF(xo[2], yo[0], zo[2]), p302=pixel3DF(xo[3], yo[0], zo[2]),
  1836. p012=pixel3DF(xo[0], yo[1], zo[2]), p112=pixel3DF(xo[1], yo[1], zo[2]), p212=pixel3DF(xo[2], yo[1], zo[2]), p312=pixel3DF(xo[3], yo[1], zo[2]),
  1837. p022=pixel3DF(xo[0], yo[2], zo[2]), p122=pixel3DF(xo[1], yo[2], zo[2]), p222=pixel3DF(xo[2], yo[2], zo[2]), p322=pixel3DF(xo[3], yo[2], zo[2]),
  1838. p032=pixel3DF(xo[0], yo[3], zo[2]), p132=pixel3DF(xo[1], yo[3], zo[2]), p232=pixel3DF(xo[2], yo[3], zo[2]), p332=pixel3DF(xo[3], yo[3], zo[2]),
  1839. p003=pixel3DF(xo[0], yo[0], zo[3]), p103=pixel3DF(xo[1], yo[0], zo[3]), p203=pixel3DF(xo[2], yo[0], zo[3]), p303=pixel3DF(xo[3], yo[0], zo[3]),
  1840. p013=pixel3DF(xo[0], yo[1], zo[3]), p113=pixel3DF(xo[1], yo[1], zo[3]), p213=pixel3DF(xo[2], yo[1], zo[3]), p313=pixel3DF(xo[3], yo[1], zo[3]),
  1841. p023=pixel3DF(xo[0], yo[2], zo[3]), p123=pixel3DF(xo[1], yo[2], zo[3]), p223=pixel3DF(xo[2], yo[2], zo[3]), p323=pixel3DF(xo[3], yo[2], zo[3]),
  1842. p033=pixel3DF(xo[0], yo[3], zo[3]), p133=pixel3DF(xo[1], yo[3], zo[3]), p233=pixel3DF(xo[2], yo[3], zo[3]), p333=pixel3DF(xo[3], yo[3], zo[3]);
  1843. #if 0
  1844. return Lerp4(
  1845. Lerp4(
  1846. Lerp4(p000, p100, p200, p300, x),
  1847. Lerp4(p010, p110, p210, p310, x),
  1848. Lerp4(p020, p120, p220, p320, x),
  1849. Lerp4(p030, p130, p230, p330, x), y),
  1850. Lerp4(
  1851. Lerp4(p001, p101, p201, p301, x),
  1852. Lerp4(p011, p111, p211, p311, x),
  1853. Lerp4(p021, p121, p221, p321, x),
  1854. Lerp4(p031, p131, p231, p331, x), y),
  1855. Lerp4(
  1856. Lerp4(p002, p102, p202, p302, x),
  1857. Lerp4(p012, p112, p212, p312, x),
  1858. Lerp4(p022, p122, p222, p322, x),
  1859. Lerp4(p032, p132, p232, p332, x), y),
  1860. Lerp4(
  1861. Lerp4(p003, p103, p203, p303, x),
  1862. Lerp4(p013, p113, p213, p313, x),
  1863. Lerp4(p023, p123, p223, p323, x),
  1864. Lerp4(p033, p133, p233, p333, x), y), z);
  1865. #else // optimized
  1866. Vec4 xb, yb; Lerp4Weights(xb, x);
  1867. Lerp4Weights(yb, y);
  1868. return Lerp4(
  1869. (p000*xb.x + p100*xb.y + p200*xb.z + p300*xb.w)*yb.x
  1870. +(p010*xb.x + p110*xb.y + p210*xb.z + p310*xb.w)*yb.y
  1871. +(p020*xb.x + p120*xb.y + p220*xb.z + p320*xb.w)*yb.z
  1872. +(p030*xb.x + p130*xb.y + p230*xb.z + p330*xb.w)*yb.w,
  1873. (p001*xb.x + p101*xb.y + p201*xb.z + p301*xb.w)*yb.x
  1874. +(p011*xb.x + p111*xb.y + p211*xb.z + p311*xb.w)*yb.y
  1875. +(p021*xb.x + p121*xb.y + p221*xb.z + p321*xb.w)*yb.z
  1876. +(p031*xb.x + p131*xb.y + p231*xb.z + p331*xb.w)*yb.w,
  1877. (p002*xb.x + p102*xb.y + p202*xb.z + p302*xb.w)*yb.x
  1878. +(p012*xb.x + p112*xb.y + p212*xb.z + p312*xb.w)*yb.y
  1879. +(p022*xb.x + p122*xb.y + p222*xb.z + p322*xb.w)*yb.z
  1880. +(p032*xb.x + p132*xb.y + p232*xb.z + p332*xb.w)*yb.w,
  1881. (p003*xb.x + p103*xb.y + p203*xb.z + p303*xb.w)*yb.x
  1882. +(p013*xb.x + p113*xb.y + p213*xb.z + p313*xb.w)*yb.y
  1883. +(p023*xb.x + p123*xb.y + p223*xb.z + p323*xb.w)*yb.z
  1884. +(p033*xb.x + p133*xb.y + p233*xb.z + p333*xb.w)*yb.w, z);
  1885. #endif
  1886. }
  1887. return 0;
  1888. }
  1889. /******************************************************************************
  1890. Flt Image::pixelFLanczosOrtho(Flt x, Flt y, Bool clamp)C
  1891. {
  1892. if(lw() && lh())
  1893. {
  1894. Int xo[LANCZOS_SAMPLES*2], yo[LANCZOS_SAMPLES*2], xi=Floor(x), yi=Floor(y);
  1895. Flt xw[LANCZOS_SAMPLES*2], yw[LANCZOS_SAMPLES*2], xs=0, ys=0;
  1896. Flt p [LANCZOS_SAMPLES*2][LANCZOS_SAMPLES*2];
  1897. REPA(xo)
  1898. {
  1899. xo[i]=xi-LANCZOS_SAMPLES+1+i; xw[i]=LanczosSharp(x-xo[i]); xs+=xw[i];
  1900. yo[i]=yi-LANCZOS_SAMPLES+1+i; yw[i]=LanczosSharp(y-yo[i]); ys+=yw[i];
  1901. if(clamp)
  1902. {
  1903. Clamp(xo[i], 0, lw()-1);
  1904. Clamp(yo[i], 0, lh()-1);
  1905. }else
  1906. {
  1907. xo[i]=Mod(xo[i], lw());
  1908. yo[i]=Mod(yo[i], lh());
  1909. }
  1910. }
  1911. gather(&p[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1912. Flt fy=0; REPAD(y, yo)
  1913. {
  1914. Flt fx=0; REPAD(x, xo)fx+=p[y][x]*xw[x];
  1915. fy+=fx*yw[y];
  1916. }
  1917. return fy/(xs*ys);
  1918. }
  1919. return 0;
  1920. }
  1921. /******************************************************************************
  1922. Vec4 Image::colorFCubicOrtho(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  1923. {
  1924. if(lw() && lh())
  1925. {
  1926. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1927. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1928. if(clamp)
  1929. {
  1930. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1931. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1932. }else
  1933. {
  1934. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1935. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1936. }
  1937. Vec4 c[4][4]; gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  1938. Vec rgb =0;
  1939. Vec4 color=0;
  1940. Vec4 xb; Lerp4Weights(xb, x);
  1941. Vec4 yb; Lerp4Weights(yb, y);
  1942. Add(color, rgb, c[0][0], xb.x*yb.x, alpha_weight);
  1943. Add(color, rgb, c[0][1], xb.y*yb.x, alpha_weight);
  1944. Add(color, rgb, c[0][2], xb.z*yb.x, alpha_weight);
  1945. Add(color, rgb, c[0][3], xb.w*yb.x, alpha_weight);
  1946. Add(color, rgb, c[1][0], xb.x*yb.y, alpha_weight);
  1947. Add(color, rgb, c[1][1], xb.y*yb.y, alpha_weight);
  1948. Add(color, rgb, c[1][2], xb.z*yb.y, alpha_weight);
  1949. Add(color, rgb, c[1][3], xb.w*yb.y, alpha_weight);
  1950. Add(color, rgb, c[2][0], xb.x*yb.z, alpha_weight);
  1951. Add(color, rgb, c[2][1], xb.y*yb.z, alpha_weight);
  1952. Add(color, rgb, c[2][2], xb.z*yb.z, alpha_weight);
  1953. Add(color, rgb, c[2][3], xb.w*yb.z, alpha_weight);
  1954. Add(color, rgb, c[3][0], xb.x*yb.w, alpha_weight);
  1955. Add(color, rgb, c[3][1], xb.y*yb.w, alpha_weight);
  1956. Add(color, rgb, c[3][2], xb.z*yb.w, alpha_weight);
  1957. Add(color, rgb, c[3][3], xb.w*yb.w, alpha_weight);
  1958. Normalize(color, rgb, alpha_weight, highPrecision());
  1959. return color;
  1960. }
  1961. return 0;
  1962. }
  1963. /******************************************************************************
  1964. Vec4 Image::color3DFCubicOrtho(Flt x, Flt y, Flt z, Bool clamp)C
  1965. {
  1966. if(lw() && lh() && ld())
  1967. {
  1968. Int xo[4]; xo[0]=Floor(x); x-=xo[0]; xo[0]--;
  1969. Int yo[4]; yo[0]=Floor(y); y-=yo[0]; yo[0]--;
  1970. Int zo[4]; zo[0]=Floor(z); z-=zo[0]; zo[0]--;
  1971. if(clamp)
  1972. {
  1973. xo[1]=Mid(xo[0]+1, 0, lw()-1); xo[2]=Mid(xo[0]+2, 0, lw()-1); xo[3]=Mid(xo[0]+3, 0, lw()-1); Clamp(xo[0], 0, lw()-1);
  1974. yo[1]=Mid(yo[0]+1, 0, lh()-1); yo[2]=Mid(yo[0]+2, 0, lh()-1); yo[3]=Mid(yo[0]+3, 0, lh()-1); Clamp(yo[0], 0, lh()-1);
  1975. zo[1]=Mid(zo[0]+1, 0, ld()-1); zo[2]=Mid(zo[0]+2, 0, ld()-1); zo[3]=Mid(zo[0]+3, 0, ld()-1); Clamp(zo[0], 0, ld()-1);
  1976. }else
  1977. {
  1978. xo[0]=Mod(xo[0], lw()); xo[1]=(xo[0]+1)%lw(); xo[2]=(xo[0]+2)%lw(); xo[3]=(xo[0]+3)%lw();
  1979. yo[0]=Mod(yo[0], lh()); yo[1]=(yo[0]+1)%lh(); yo[2]=(yo[0]+2)%lh(); yo[3]=(yo[0]+3)%lh();
  1980. zo[0]=Mod(zo[0], ld()); zo[1]=(zo[0]+1)%ld(); zo[2]=(zo[0]+2)%ld(); zo[3]=(zo[0]+3)%ld();
  1981. }
  1982. Vec4 c000=color3DF(xo[0], yo[0], zo[0]), c100=color3DF(xo[1], yo[0], zo[0]), c200=color3DF(xo[2], yo[0], zo[0]), c300=color3DF(xo[3], yo[0], zo[0]),
  1983. c010=color3DF(xo[0], yo[1], zo[0]), c110=color3DF(xo[1], yo[1], zo[0]), c210=color3DF(xo[2], yo[1], zo[0]), c310=color3DF(xo[3], yo[1], zo[0]),
  1984. c020=color3DF(xo[0], yo[2], zo[0]), c120=color3DF(xo[1], yo[2], zo[0]), c220=color3DF(xo[2], yo[2], zo[0]), c320=color3DF(xo[3], yo[2], zo[0]),
  1985. c030=color3DF(xo[0], yo[3], zo[0]), c130=color3DF(xo[1], yo[3], zo[0]), c230=color3DF(xo[2], yo[3], zo[0]), c330=color3DF(xo[3], yo[3], zo[0]),
  1986. c001=color3DF(xo[0], yo[0], zo[1]), c101=color3DF(xo[1], yo[0], zo[1]), c201=color3DF(xo[2], yo[0], zo[1]), c301=color3DF(xo[3], yo[0], zo[1]),
  1987. c011=color3DF(xo[0], yo[1], zo[1]), c111=color3DF(xo[1], yo[1], zo[1]), c211=color3DF(xo[2], yo[1], zo[1]), c311=color3DF(xo[3], yo[1], zo[1]),
  1988. c021=color3DF(xo[0], yo[2], zo[1]), c121=color3DF(xo[1], yo[2], zo[1]), c221=color3DF(xo[2], yo[2], zo[1]), c321=color3DF(xo[3], yo[2], zo[1]),
  1989. c031=color3DF(xo[0], yo[3], zo[1]), c131=color3DF(xo[1], yo[3], zo[1]), c231=color3DF(xo[2], yo[3], zo[1]), c331=color3DF(xo[3], yo[3], zo[1]),
  1990. c002=color3DF(xo[0], yo[0], zo[2]), c102=color3DF(xo[1], yo[0], zo[2]), c202=color3DF(xo[2], yo[0], zo[2]), c302=color3DF(xo[3], yo[0], zo[2]),
  1991. c012=color3DF(xo[0], yo[1], zo[2]), c112=color3DF(xo[1], yo[1], zo[2]), c212=color3DF(xo[2], yo[1], zo[2]), c312=color3DF(xo[3], yo[1], zo[2]),
  1992. c022=color3DF(xo[0], yo[2], zo[2]), c122=color3DF(xo[1], yo[2], zo[2]), c222=color3DF(xo[2], yo[2], zo[2]), c322=color3DF(xo[3], yo[2], zo[2]),
  1993. c032=color3DF(xo[0], yo[3], zo[2]), c132=color3DF(xo[1], yo[3], zo[2]), c232=color3DF(xo[2], yo[3], zo[2]), c332=color3DF(xo[3], yo[3], zo[2]),
  1994. c003=color3DF(xo[0], yo[0], zo[3]), c103=color3DF(xo[1], yo[0], zo[3]), c203=color3DF(xo[2], yo[0], zo[3]), c303=color3DF(xo[3], yo[0], zo[3]),
  1995. c013=color3DF(xo[0], yo[1], zo[3]), c113=color3DF(xo[1], yo[1], zo[3]), c213=color3DF(xo[2], yo[1], zo[3]), c313=color3DF(xo[3], yo[1], zo[3]),
  1996. c023=color3DF(xo[0], yo[2], zo[3]), c123=color3DF(xo[1], yo[2], zo[3]), c223=color3DF(xo[2], yo[2], zo[3]), c323=color3DF(xo[3], yo[2], zo[3]),
  1997. c033=color3DF(xo[0], yo[3], zo[3]), c133=color3DF(xo[1], yo[3], zo[3]), c233=color3DF(xo[2], yo[3], zo[3]), c333=color3DF(xo[3], yo[3], zo[3]);
  1998. #if 0
  1999. return Lerp4(
  2000. Lerp4(
  2001. Lerp4(c000, c100, c200, c300, x),
  2002. Lerp4(c010, c110, c210, c310, x),
  2003. Lerp4(c020, c120, c220, c320, x),
  2004. Lerp4(c030, c130, c230, c330, x), y),
  2005. Lerp4(
  2006. Lerp4(c001, c101, c201, c301, x),
  2007. Lerp4(c011, c111, c211, c311, x),
  2008. Lerp4(c021, c121, c221, c321, x),
  2009. Lerp4(c031, c131, c231, c331, x), y),
  2010. Lerp4(
  2011. Lerp4(c002, c102, c202, c302, x),
  2012. Lerp4(c012, c112, c212, c312, x),
  2013. Lerp4(c022, c122, c222, c322, x),
  2014. Lerp4(c032, c132, c232, c332, x), y),
  2015. Lerp4(
  2016. Lerp4(c003, c103, c203, c303, x),
  2017. Lerp4(c013, c113, c213, c313, x),
  2018. Lerp4(c023, c123, c223, c323, x),
  2019. Lerp4(c033, c133, c233, c333, x), y), z);
  2020. #else // optimized
  2021. Vec4 xb, yb; Lerp4Weights(xb, x);
  2022. Lerp4Weights(yb, y);
  2023. return Lerp4(
  2024. (c000*xb.x + c100*xb.y + c200*xb.z + c300*xb.w)*yb.x
  2025. +(c010*xb.x + c110*xb.y + c210*xb.z + c310*xb.w)*yb.y
  2026. +(c020*xb.x + c120*xb.y + c220*xb.z + c320*xb.w)*yb.z
  2027. +(c030*xb.x + c130*xb.y + c230*xb.z + c330*xb.w)*yb.w,
  2028. (c001*xb.x + c101*xb.y + c201*xb.z + c301*xb.w)*yb.x
  2029. +(c011*xb.x + c111*xb.y + c211*xb.z + c311*xb.w)*yb.y
  2030. +(c021*xb.x + c121*xb.y + c221*xb.z + c321*xb.w)*yb.z
  2031. +(c031*xb.x + c131*xb.y + c231*xb.z + c331*xb.w)*yb.w,
  2032. (c002*xb.x + c102*xb.y + c202*xb.z + c302*xb.w)*yb.x
  2033. +(c012*xb.x + c112*xb.y + c212*xb.z + c312*xb.w)*yb.y
  2034. +(c022*xb.x + c122*xb.y + c222*xb.z + c322*xb.w)*yb.z
  2035. +(c032*xb.x + c132*xb.y + c232*xb.z + c332*xb.w)*yb.w,
  2036. (c003*xb.x + c103*xb.y + c203*xb.z + c303*xb.w)*yb.x
  2037. +(c013*xb.x + c113*xb.y + c213*xb.z + c313*xb.w)*yb.y
  2038. +(c023*xb.x + c123*xb.y + c223*xb.z + c323*xb.w)*yb.z
  2039. +(c033*xb.x + c133*xb.y + c233*xb.z + c333*xb.w)*yb.w, z);
  2040. #endif
  2041. }
  2042. return 0;
  2043. }
  2044. /******************************************************************************
  2045. Vec4 Image::colorFLanczosOrtho(Flt x, Flt y, Bool clamp, Bool alpha_weight)C
  2046. {
  2047. if(lw() && lh())
  2048. {
  2049. Int xo[LANCZOS_SAMPLES*2], yo[LANCZOS_SAMPLES*2], xi=Floor(x), yi=Floor(y);
  2050. Flt xw[LANCZOS_SAMPLES*2], yw[LANCZOS_SAMPLES*2], xs=0, ys=0;
  2051. Vec4 c [LANCZOS_SAMPLES*2][LANCZOS_SAMPLES*2];
  2052. REPA(xo)
  2053. {
  2054. xo[i]=xi-LANCZOS_SAMPLES+1+i; xw[i]=LanczosSharp(x-xo[i]); xs+=xw[i];
  2055. yo[i]=yi-LANCZOS_SAMPLES+1+i; yw[i]=LanczosSharp(y-yo[i]); ys+=yw[i];
  2056. if(clamp)
  2057. {
  2058. Clamp(xo[i], 0, lw()-1);
  2059. Clamp(yo[i], 0, lh()-1);
  2060. }else
  2061. {
  2062. xo[i]=Mod(xo[i], lw());
  2063. yo[i]=Mod(yo[i], lh());
  2064. }
  2065. }
  2066. gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  2067. Vec rgb =0;
  2068. Vec4 color=0;
  2069. REPAD(y, yo)
  2070. REPAD(x, xo)Add(color, rgb, c[y][x], xw[x]*yw[y], alpha_weight);
  2071. Normalize(color, rgb, alpha_weight, highPrecision());
  2072. return color/(xs*ys);
  2073. }
  2074. return 0;
  2075. }
  2076. /******************************************************************************
  2077. Flt Image::pixel3DFLanczosOrtho(Flt x, Flt y, Flt z, Bool clamp)C
  2078. {
  2079. if(lw() && lh() && ld())
  2080. {
  2081. Int xo[LANCZOS_SAMPLES*2], yo[LANCZOS_SAMPLES*2], zc[LANCZOS_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  2082. Flt xw[LANCZOS_SAMPLES*2], yw[LANCZOS_SAMPLES*2], zw[LANCZOS_SAMPLES*2], xs=0, ys=0, zs=0;
  2083. REPA(xo)
  2084. {
  2085. xo[i]=xi-LANCZOS_SAMPLES+1+i; xw[i]=LanczosSharp(x-xo[i]); xs+=xw[i];
  2086. yo[i]=yi-LANCZOS_SAMPLES+1+i; yw[i]=LanczosSharp(y-yo[i]); ys+=yw[i];
  2087. zc[i]=zi-LANCZOS_SAMPLES+1+i; zw[i]=LanczosSharp(z-zc[i]); zs+=zw[i];
  2088. if(clamp)
  2089. {
  2090. Clamp(xo[i], 0, lw()-1);
  2091. Clamp(yo[i], 0, lh()-1);
  2092. Clamp(zc[i], 0, ld()-1);
  2093. }else
  2094. {
  2095. xo[i]=Mod(xo[i], lw());
  2096. yo[i]=Mod(yo[i], lh());
  2097. zc[i]=Mod(zc[i], ld());
  2098. }
  2099. }
  2100. Flt fz=0; REPAD(z, zc)
  2101. {
  2102. Flt fy=0; REPAD(y, yo)
  2103. {
  2104. Flt fx=0; REPAD(x, xo)fx+=pixel3DF(xo[x], yo[y], zc[z])*xw[x];
  2105. fy+=fx*yw[y];
  2106. }
  2107. fz+=fy*zw[z];
  2108. }
  2109. return fz/(xs*ys*zs);
  2110. }
  2111. return 0;
  2112. }
  2113. /******************************************************************************
  2114. Vec4 Image::color3DFLanczosOrtho(Flt x, Flt y, Flt z, Bool clamp)C
  2115. {
  2116. if(lw() && lh() && ld())
  2117. {
  2118. Int xo[LANCZOS_SAMPLES*2], yo[LANCZOS_SAMPLES*2], zc[LANCZOS_SAMPLES*2], xi=Floor(x), yi=Floor(y), zi=Floor(z);
  2119. Flt xw[LANCZOS_SAMPLES*2], yw[LANCZOS_SAMPLES*2], zw[LANCZOS_SAMPLES*2], xs=0, ys=0, zs=0;
  2120. REPA(xo)
  2121. {
  2122. xo[i]=xi-LANCZOS_SAMPLES+1+i; xw[i]=LanczosSharp(x-xo[i]); xs+=xw[i];
  2123. yo[i]=yi-LANCZOS_SAMPLES+1+i; yw[i]=LanczosSharp(y-yo[i]); ys+=yw[i];
  2124. zc[i]=zi-LANCZOS_SAMPLES+1+i; zw[i]=LanczosSharp(z-zc[i]); zs+=zw[i];
  2125. if(clamp)
  2126. {
  2127. Clamp(xo[i], 0, lw()-1);
  2128. Clamp(yo[i], 0, lh()-1);
  2129. Clamp(zc[i], 0, ld()-1);
  2130. }else
  2131. {
  2132. xo[i]=Mod(xo[i], lw());
  2133. yo[i]=Mod(yo[i], lh());
  2134. zc[i]=Mod(zc[i], ld());
  2135. }
  2136. }
  2137. Vec4 cz=0; REPAD(z, zc)
  2138. {
  2139. Vec4 cy=0; REPAD(y, yo)
  2140. {
  2141. Vec4 cx=0; REPAD(x, xo)cx+=color3DF(xo[x], yo[y], zc[z])*xw[x];
  2142. cy+=cx*yw[y];
  2143. }
  2144. cz+=cy*zw[z];
  2145. }
  2146. return cz/(xs*ys*zs);
  2147. }
  2148. return 0;
  2149. }
  2150. /******************************************************************************/
  2151. // AREA
  2152. /******************************************************************************/
  2153. Vec4 Image::areaColorAverage(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2154. {
  2155. if(lw() && lh())
  2156. {
  2157. Rect_C rect (pos, Max(size.x-1, 0), Max(size.y-1, 0)); // 'size' here means scale, subtract 1 to convert to inclusive coordinates
  2158. RectI recti(Floor(rect.min.x), Floor(rect.min.y), Ceil(rect.max.x), Ceil(rect.max.y)); // inclusive coordinates. Have to use Ceil for max, because we need to process the neighbor pixel too (for example if rect.min.x=0.5 and rect.max.x=0.5, then we need to process both x=0 and x=1 pixels)
  2159. Int xo[2], yo[2];
  2160. if(clamp)
  2161. {
  2162. xo[0]=Mid(recti.min.x, 0, lw()-1); yo[0]=Mid(recti.min.y, 0, lh()-1);
  2163. xo[1]=Mid(recti.max.x, 0, lw()-1); yo[1]=Mid(recti.max.y, 0, lh()-1);
  2164. }else
  2165. {
  2166. xo[0]=Mod(recti.min.x, lw()); yo[0]=Mod(recti.min.y, lh());
  2167. xo[1]=Mod(recti.max.x, lw()); yo[1]=Mod(recti.max.y, lh());
  2168. }
  2169. if(recti.min==recti.max)return colorF(xo[0], yo[0]); // if coordinates are the same, then return this pixel
  2170. // calculate blending factors
  2171. Flt l=1+recti.min.x-rect.min.x, r=1+rect.max.x-recti.max.x, // l=1-(rect.min.x-recti.min.x), r=1-(recti.max.x-rect.max.x)
  2172. t=1+recti.min.y-rect.min.y, b=1+rect.max.y-recti.max.y; // t=1-(rect.min.y-recti.min.y), b=1-(recti.max.y-rect.max.y)
  2173. Vec rgb =0;
  2174. Vec4 color=0;
  2175. // add inside
  2176. for(Int y=recti.min.y+1; y<recti.max.y; y++)
  2177. for(Int yo=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh())), x=recti.min.x+1; x<recti.max.x; x++)Add(color, rgb, colorF(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()), yo), alpha_weight);
  2178. // add sides
  2179. if(recti.min.y==recti.max.y)
  2180. for(Int x=recti.min.x+1; x<recti.max.x; x++)
  2181. {
  2182. Int xo=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()));
  2183. Add(color, rgb, colorF(xo, yo[0]), alpha_weight);
  2184. }else
  2185. for(Int x=recti.min.x+1; x<recti.max.x; x++)
  2186. {
  2187. Int xo=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()));
  2188. Vec4 c[2]; gather(c, &xo, 1, yo, Elms(yo));
  2189. Add(color, rgb, c[0], t, alpha_weight); // top
  2190. Add(color, rgb, c[1], b, alpha_weight); // bottom
  2191. }
  2192. if(recti.min.x==recti.max.x)
  2193. for(Int y=recti.min.y+1; y<recti.max.y; y++)
  2194. {
  2195. Int yo=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2196. Add(color, rgb, colorF(xo[0], yo), alpha_weight);
  2197. }else
  2198. for(Int y=recti.min.y+1; y<recti.max.y; y++)
  2199. {
  2200. Int yo=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2201. Vec4 c[2]; gather(c, xo, Elms(xo), &yo, 1);
  2202. Add(color, rgb, c[0], l, alpha_weight); // left
  2203. Add(color, rgb, c[1], r, alpha_weight); // right
  2204. }
  2205. // add corners
  2206. if(recti.min.y==recti.max.y)
  2207. {
  2208. Vec4 c[2]; gather(&c[0], xo, Elms(xo), yo, 1);
  2209. Add(color, rgb, c[0], l, alpha_weight);
  2210. Add(color, rgb, c[1], r, alpha_weight);
  2211. }else
  2212. if(recti.min.x==recti.max.x)
  2213. {
  2214. Vec4 c[2]; gather(&c[0], xo, 1, yo, Elms(yo));
  2215. Add(color, rgb, c[0], t, alpha_weight);
  2216. Add(color, rgb, c[1], b, alpha_weight);
  2217. }else
  2218. {
  2219. Vec4 c[2][2]; gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  2220. Add(color, rgb, c[0][0], l*t, alpha_weight);
  2221. Add(color, rgb, c[0][1], r*t, alpha_weight);
  2222. Add(color, rgb, c[1][0], l*b, alpha_weight);
  2223. Add(color, rgb, c[1][1], r*b, alpha_weight);
  2224. }
  2225. Normalize(color, rgb, (rect.w()+1)*(rect.h()+1), alpha_weight, highPrecision()); // weight is always non-zero here
  2226. return color;
  2227. }
  2228. return 0;
  2229. }
  2230. /******************************************************************************/
  2231. Vec4 Image::areaColorLinear(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C // this is orthogonal
  2232. {
  2233. if(lw() && lh())
  2234. {
  2235. // f=(p-center)/size
  2236. const Vec2 s(Max(1, size.x*0.75f), Max(1, size.y*0.75f)); // 0.5 is too sharp, 1.0 is too blurry, 0.75 is best and gives same results as Avg(a,b)
  2237. Vec2 x_mul_add; x_mul_add.x=1/s.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2238. Vec2 y_mul_add; y_mul_add.x=1/s.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2239. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2240. Int x0=CeilSpecial(pos.x-s.x), x1=FloorSpecial(pos.x+s.x),
  2241. y0=CeilSpecial(pos.y-s.y), y1=FloorSpecial(pos.y+s.y);
  2242. Flt weight=0; // this is always non-zero
  2243. Vec rgb =0;
  2244. Vec4 color =0;
  2245. for(Int y=y0; y<=y1; y++)
  2246. {
  2247. Flt fy=y*y_mul_add.x + y_mul_add.y; fy=Linear(fy); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2248. for(Int x=x0; x<=x1; x++)
  2249. {
  2250. Flt fx=x*x_mul_add.x + x_mul_add.y; fx=Linear(fx); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()));
  2251. fx*=fy;
  2252. Add(color, rgb, colorF(xi, yi), fx, alpha_weight); weight+=fx;
  2253. }
  2254. }
  2255. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2256. return color;
  2257. }
  2258. return 0;
  2259. }
  2260. /******************************************************************************/
  2261. Vec4 Image::areaColorCubicFast(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2262. {
  2263. if(lw() && lh())
  2264. {
  2265. // f=(p-center)/size
  2266. const Vec2 size_a(Max(CUBIC_FAST_RANGE, size.x*CUBIC_FAST_RANGE), Max(CUBIC_FAST_RANGE, size.y*CUBIC_FAST_RANGE));
  2267. Vec2 x_mul_add; x_mul_add.x=CUBIC_FAST_RANGE/size_a.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2268. Vec2 y_mul_add; y_mul_add.x=CUBIC_FAST_RANGE/size_a.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2269. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2270. Int x0=CeilSpecial(pos.x-size_a.x), x1=FloorSpecial(pos.x+size_a.x),
  2271. y0=CeilSpecial(pos.y-size_a.y), y1=FloorSpecial(pos.y+size_a.y);
  2272. Flt weight=0; // this is always non-zero
  2273. Vec rgb =0;
  2274. Vec4 color =0;
  2275. for(Int y=y0; y<=y1; y++)
  2276. {
  2277. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2278. for(Int x=x0; x<=x1; x++)
  2279. {
  2280. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2281. if(w<Sqr(CUBIC_FAST_RANGE))
  2282. {
  2283. w=CubicFast2(w); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw())); Add(color, rgb, colorF(xi, yi), w, alpha_weight); weight+=w;
  2284. }
  2285. }
  2286. }
  2287. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2288. return color;
  2289. }
  2290. return 0;
  2291. }
  2292. Vec4 Image::areaColorCubicFastSmooth(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2293. {
  2294. if(lw() && lh())
  2295. {
  2296. // f=(p-center)/size
  2297. const Vec2 size_a(Max(CUBIC_FAST_RANGE, size.x*CUBIC_FAST_RANGE), Max(CUBIC_FAST_RANGE, size.y*CUBIC_FAST_RANGE));
  2298. Vec2 x_mul_add; x_mul_add.x=CUBIC_FAST_RANGE/size_a.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2299. Vec2 y_mul_add; y_mul_add.x=CUBIC_FAST_RANGE/size_a.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2300. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2301. Int x0=CeilSpecial(pos.x-size_a.x), x1=FloorSpecial(pos.x+size_a.x),
  2302. y0=CeilSpecial(pos.y-size_a.y), y1=FloorSpecial(pos.y+size_a.y);
  2303. Flt weight=0; // this is always non-zero
  2304. Vec rgb =0;
  2305. Vec4 color =0;
  2306. for(Int y=y0; y<=y1; y++)
  2307. {
  2308. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2309. for(Int x=x0; x<=x1; x++)
  2310. {
  2311. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2312. if(w<Sqr(CUBIC_FAST_RANGE))
  2313. {
  2314. w=CubicFastSmooth2(w); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw())); Add(color, rgb, colorF(xi, yi), w, alpha_weight); weight+=w;
  2315. }
  2316. }
  2317. }
  2318. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2319. return color;
  2320. }
  2321. return 0;
  2322. }
  2323. Vec4 Image::areaColorCubicFastSharp(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2324. {
  2325. if(lw() && lh())
  2326. {
  2327. // f=(p-center)/size
  2328. const Vec2 size_a(Max(CUBIC_FAST_RANGE, size.x*CUBIC_FAST_RANGE), Max(CUBIC_FAST_RANGE, size.y*CUBIC_FAST_RANGE));
  2329. Vec2 x_mul_add; x_mul_add.x=CUBIC_FAST_RANGE/size_a.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2330. Vec2 y_mul_add; y_mul_add.x=CUBIC_FAST_RANGE/size_a.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2331. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2332. Int x0=CeilSpecial(pos.x-size_a.x), x1=FloorSpecial(pos.x+size_a.x),
  2333. y0=CeilSpecial(pos.y-size_a.y), y1=FloorSpecial(pos.y+size_a.y);
  2334. Flt weight=0; // this is always non-zero
  2335. Vec rgb =0;
  2336. Vec4 color =0;
  2337. for(Int y=y0; y<=y1; y++)
  2338. {
  2339. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2340. for(Int x=x0; x<=x1; x++)
  2341. {
  2342. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2343. if(w<Sqr(CUBIC_FAST_RANGE))
  2344. {
  2345. w=CubicFastSharp2(w); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw())); Add(color, rgb, colorF(xi, yi), w, alpha_weight); weight+=w;
  2346. }
  2347. }
  2348. }
  2349. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2350. return color;
  2351. }
  2352. return 0;
  2353. }
  2354. Vec4 Image::areaColorCubic(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2355. {
  2356. if(lw() && lh())
  2357. {
  2358. // f=(p-center)/size
  2359. const Vec2 size_a(Max(CUBIC_MED_RANGE, size.x*CUBIC_MED_RANGE), Max(CUBIC_MED_RANGE, size.y*CUBIC_MED_RANGE));
  2360. Vec2 x_mul_add; x_mul_add.x=CUBIC_MED_RANGE/size_a.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2361. Vec2 y_mul_add; y_mul_add.x=CUBIC_MED_RANGE/size_a.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2362. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2363. Int x0=CeilSpecial(pos.x-size_a.x), x1=FloorSpecial(pos.x+size_a.x),
  2364. y0=CeilSpecial(pos.y-size_a.y), y1=FloorSpecial(pos.y+size_a.y);
  2365. Flt weight=0; // this is always non-zero
  2366. Vec rgb =0;
  2367. Vec4 color =0;
  2368. for(Int y=y0; y<=y1; y++)
  2369. {
  2370. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2371. for(Int x=x0; x<=x1; x++)
  2372. {
  2373. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2374. if(w<Sqr(CUBIC_MED_RANGE))
  2375. {
  2376. w=CubicMed2(w*Sqr(CUBIC_MED_SHARPNESS)); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw())); Add(color, rgb, colorF(xi, yi), w, alpha_weight); weight+=w;
  2377. }
  2378. }
  2379. }
  2380. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2381. return color;
  2382. }
  2383. return 0;
  2384. }
  2385. Vec4 Image::areaColorCubicSharp(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2386. {
  2387. if(lw() && lh())
  2388. {
  2389. // f=(p-center)/size
  2390. const Vec2 size_a(Max(CUBIC_SHARP_RANGE, size.x*CUBIC_SHARP_RANGE), Max(CUBIC_SHARP_RANGE, size.y*CUBIC_SHARP_RANGE));
  2391. Vec2 x_mul_add; x_mul_add.x=CUBIC_SHARP_RANGE/size_a.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2392. Vec2 y_mul_add; y_mul_add.x=CUBIC_SHARP_RANGE/size_a.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2393. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2394. Int x0=CeilSpecial(pos.x-size_a.x), x1=FloorSpecial(pos.x+size_a.x),
  2395. y0=CeilSpecial(pos.y-size_a.y), y1=FloorSpecial(pos.y+size_a.y);
  2396. Flt weight=0; // this is always non-zero
  2397. Vec rgb =0;
  2398. Vec4 color =0;
  2399. for(Int y=y0; y<=y1; y++)
  2400. {
  2401. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2402. for(Int x=x0; x<=x1; x++)
  2403. {
  2404. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2405. if(w<Sqr(CUBIC_SHARP_RANGE))
  2406. {
  2407. w=CubicSharp2(w*Sqr(CUBIC_SHARP_SHARPNESS)); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw())); Add(color, rgb, colorF(xi, yi), w, alpha_weight); weight+=w;
  2408. }
  2409. }
  2410. }
  2411. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2412. return color;
  2413. }
  2414. return 0;
  2415. }
  2416. /******************************************************************************
  2417. Vec4 Image::areaColorCubicOrtho(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2418. {
  2419. if(lw() && lh())
  2420. {
  2421. // f=(p-center)/size
  2422. const Vec2 size_2(Max(2, size.x*2), Max(2, size.y*2));
  2423. Vec2 x_mul_add; x_mul_add.x=2/size_2.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2424. Vec2 y_mul_add; y_mul_add.x=2/size_2.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2425. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2426. Int x0=CeilSpecial(pos.x-size_2.x), x1=FloorSpecial(pos.x+size_2.x),
  2427. y0=CeilSpecial(pos.y-size_2.y), y1=FloorSpecial(pos.y+size_2.y);
  2428. Flt weight=0; // this is always non-zero
  2429. Vec rgb =0;
  2430. Vec4 color =0;
  2431. for(Int y=y0; y<=y1; y++)
  2432. {
  2433. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2434. for(Int x=x0; x<=x1; x++)
  2435. {
  2436. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2437. if(w<4) // Cubic returns 0 for values >=2, since we use Sqr, check for 4
  2438. {
  2439. w=CubicSmoothFast2(w); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw())); Add(color, rgb, colorF(xi, yi), w, alpha_weight); weight+=w;
  2440. }
  2441. }
  2442. }
  2443. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2444. return color;
  2445. }
  2446. return 0;
  2447. }
  2448. Vec4 Image::areaColorCubicOrtho(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2449. {
  2450. if(lw() && lh())
  2451. {
  2452. // f=(p-center)/size
  2453. const Vec2 size_2(Max(2, size.x*2), Max(2, size.y*2));
  2454. Vec2 x_mul_add; x_mul_add.x=2/size_2.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2455. Vec2 y_mul_add; y_mul_add.x=2/size_2.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2456. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2457. Int x0=CeilSpecial(pos.x-size_2.x), x1=FloorSpecial(pos.x+size_2.x),
  2458. y0=CeilSpecial(pos.y-size_2.y), y1=FloorSpecial(pos.y+size_2.y);
  2459. Flt weight=0; // this is always non-zero
  2460. Vec rgb =0;
  2461. Vec4 color =0;
  2462. for(Int y=y0; y<=y1; y++)
  2463. {
  2464. Flt fy=y*y_mul_add.x + y_mul_add.y; fy=CubicFastSharp(fy); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2465. for(Int x=x0; x<=x1; x++)
  2466. {
  2467. Flt fx=x*x_mul_add.x + x_mul_add.y; fx=CubicFastSharp(fx); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()));
  2468. fx*=fy;
  2469. Add(color, rgb, colorF(xi, yi), fx, alpha_weight); weight+=fx;
  2470. }
  2471. }
  2472. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2473. return color;
  2474. }
  2475. return 0;
  2476. }
  2477. /******************************************************************************
  2478. Vec4 Image::areaColorCubicSharpGammaCorrect(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2479. {
  2480. if(lw() && lh())
  2481. {
  2482. // f=(p-center)/size
  2483. const Vec2 size_2(Max(2, size.x*2), Max(2, size.y*2));
  2484. Vec2 x_mul_add; x_mul_add.x=2/size_2.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2485. Vec2 y_mul_add; y_mul_add.x=2/size_2.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2486. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2487. Int x0=CeilSpecial(pos.x-size_2.x), x1=FloorSpecial(pos.x+size_2.x),
  2488. y0=CeilSpecial(pos.y-size_2.y), y1=FloorSpecial(pos.y+size_2.y);
  2489. Flt weight=0; // this is always non-zero
  2490. Vec rgb =0;
  2491. Vec4 color =0;
  2492. Vec lin_srgb =0;
  2493. Vec4 lin_scolor =0;
  2494. Flt lin_weight=0;
  2495. Vec lin_rgb =0;
  2496. Vec4 lin_color =0;
  2497. for(Int y=y0; y<=y1; y++)
  2498. {
  2499. Flt fy2=Sqr(y*y_mul_add.x + y_mul_add.y); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2500. for(Int x=x0; x<=x1; x++)
  2501. {
  2502. Flt fx2=Sqr(x*x_mul_add.x + x_mul_add.y), w=fx2+fy2;
  2503. if(w<4) // Cubic returns 0 for values >=2, since we use Sqr, check for 4
  2504. {
  2505. Flt W=CubicSharpFast2(w); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()));
  2506. Vec4 c=colorF(xi, yi);
  2507. Add(color, rgb, c, W, alpha_weight); weight+=W;
  2508. if(w<1)
  2509. {
  2510. w=Linear(SqrtFast(w));
  2511. Add(lin_scolor, lin_srgb, c, w, alpha_weight);
  2512. //c.x=SRGBToLinear(c.x);
  2513. //c.y=SRGBToLinear(c.y);
  2514. //c.z=SRGBToLinear(c.z);
  2515. c.x=Pow(c.x, 1.18f);
  2516. c.y=Pow(c.y, 1.18f);
  2517. c.z=Pow(c.z, 1.18f);
  2518. Add(lin_color, lin_rgb, c, w, alpha_weight); lin_weight+=w;
  2519. }
  2520. }
  2521. }
  2522. }
  2523. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2524. Normalize(lin_scolor, lin_srgb, lin_weight, alpha_weight, highPrecision());
  2525. Normalize(lin_color, lin_rgb, lin_weight, alpha_weight, highPrecision());
  2526. //lin_color.x=LinearToSRGB(lin_color.x);
  2527. //lin_color.y=LinearToSRGB(lin_color.y);
  2528. //lin_color.z=LinearToSRGB(lin_color.z);
  2529. lin_color.x=Pow(lin_color.x, 1.0f/1.18f);
  2530. lin_color.y=Pow(lin_color.y, 1.0f/1.18f);
  2531. lin_color.z=Pow(lin_color.z, 1.0f/1.18f);
  2532. return lin_color+color-lin_scolor;
  2533. }
  2534. return 0;
  2535. }
  2536. /******************************************************************************
  2537. Vec4 Image::areaColorLanczosOrtho(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C
  2538. {
  2539. if(lw() && lh())
  2540. {
  2541. // f=(p-center)/size
  2542. const Vec2 size_a(Max(LANCZOS_SAMPLES, size.x*LANCZOS_SAMPLES), Max(LANCZOS_SAMPLES, size.y*LANCZOS_SAMPLES));
  2543. Vec2 x_mul_add; x_mul_add.x=LANCZOS_SAMPLES/size_a.x; x_mul_add.y=-pos.x*x_mul_add.x;
  2544. Vec2 y_mul_add; y_mul_add.x=LANCZOS_SAMPLES/size_a.y; y_mul_add.y=-pos.y*y_mul_add.x;
  2545. // ceil is used for min, and floor used for max, because these are coordinates at which the weight function is zero, so we need to process next/previous pixels because they will be the first ones with some weight
  2546. Int x0=CeilSpecial(pos.x-size_a.x), x1=FloorSpecial(pos.x+size_a.x),
  2547. y0=CeilSpecial(pos.y-size_a.y), y1=FloorSpecial(pos.y+size_a.y);
  2548. Flt weight=0; // this is always non-zero
  2549. Vec rgb =0;
  2550. Vec4 color =0;
  2551. for(Int y=y0; y<=y1; y++)
  2552. {
  2553. Flt fy=y*y_mul_add.x + y_mul_add.y; fy=LanczosSharp(fy); Int yi=(clamp ? Mid(y, 0, lh()-1) : Mod(y, lh()));
  2554. for(Int x=x0; x<=x1; x++)
  2555. {
  2556. Flt fx=x*x_mul_add.x + x_mul_add.y; fx=LanczosSharp(fx); Int xi=(clamp ? Mid(x, 0, lw()-1) : Mod(x, lw()));
  2557. fx*=fy;
  2558. Add(color, rgb, colorF(xi, yi), fx, alpha_weight); weight+=fx;
  2559. }
  2560. }
  2561. Normalize(color, rgb, weight, alpha_weight, highPrecision());
  2562. return color;
  2563. }
  2564. return 0;
  2565. }
  2566. /******************************************************************************/
  2567. #if 1 // faster, but reaches max 254 values instead of 255
  2568. static inline Byte SByteToByte(SByte s) {return (s<=0) ? 0 : (s<<1);}
  2569. #else
  2570. static inline Byte SByteToByte(SByte s) {return (s<=0) ? 0 : (s*255+63)/127;}
  2571. #endif
  2572. /******************************************************************************/
  2573. static Color PixelToColor(IMAGE_TYPE type, UInt pixel) // convert pixel to color
  2574. {
  2575. switch(type)
  2576. {
  2577. case IMAGE_B8G8R8A8: return Color((pixel>>16)&0xFF, (pixel>> 8)&0xFF, pixel &0xFF, pixel>>24);
  2578. case IMAGE_R8G8B8A8: return Color( pixel &0xFF, (pixel>> 8)&0xFF, (pixel>>16)&0xFF, pixel>>24);
  2579. case IMAGE_R8G8B8 : return Color( pixel &0xFF, (pixel>> 8)&0xFF, (pixel>>16)&0xFF, 255);
  2580. case IMAGE_R8G8 : return Color( pixel &0xFF, (pixel>> 8)&0xFF, 0, 255);
  2581. case IMAGE_R8 : return Color( pixel &0xFF, 0, 0, 255);
  2582. case IMAGE_A8 : return Color( 0, 0, 0, pixel );
  2583. case IMAGE_L8 : return Color( pixel , pixel , pixel , 255);
  2584. case IMAGE_L8A8 : return Color( pixel &0xFF, pixel &0xFF, pixel&0xFF , pixel>> 8);
  2585. case IMAGE_I8 : return Color( pixel , pixel , pixel , 255);
  2586. case IMAGE_I16 : return Color( pixel>> 8 , pixel>>8 , pixel>>8 , 255);
  2587. case IMAGE_I24 : return Color( pixel>>16 , pixel>>16 , pixel>>16 , 255);
  2588. case IMAGE_I32 : return Color( pixel>>24 , pixel>>24 , pixel>>24 , 255);
  2589. default : return Color( 0, 0, 0, 0);
  2590. case IMAGE_BC1 :
  2591. case IMAGE_BC2 :
  2592. case IMAGE_BC3 :
  2593. case IMAGE_BC7 :
  2594. case IMAGE_PVRTC1_2:
  2595. case IMAGE_PVRTC1_4:
  2596. case IMAGE_ETC1 :
  2597. case IMAGE_ETC2 :
  2598. case IMAGE_ETC2_A1 :
  2599. case IMAGE_ETC2_A8 : return Color(pixel&0xFF, (pixel>>8)&0xFF, (pixel>>16)&0xFF, pixel>>24);
  2600. case IMAGE_B4G4R4X4 : return Color(((pixel>> 8)&0x0F)<<4, ((pixel>> 4)&0x0F)<<4, ((pixel )&0x0F)<<4, 255);
  2601. case IMAGE_B4G4R4A4 : return Color(((pixel>> 8)&0x0F)<<4, ((pixel>> 4)&0x0F)<<4, ((pixel )&0x0F)<<4, ((pixel>>12)&0x0F)<<4 );
  2602. case IMAGE_B5G5R5X1 : return Color(((pixel>>10)&0x1F)<<3, ((pixel>> 5)&0x1F)<<3, ((pixel )&0x1F)<<3, 255);
  2603. case IMAGE_B5G5R5A1 : return Color(((pixel>>10)&0x1F)<<3, ((pixel>> 5)&0x1F)<<3, ((pixel )&0x1F)<<3, (pixel&0x8000) ? 255 : 0);
  2604. case IMAGE_B5G6R5 : return Color(((pixel>>11)&0x1F)<<3, ((pixel>> 5)&0x3F)<<2, ((pixel )&0x1F)<<3, 255);
  2605. case IMAGE_B8G8R8 : return Color( (pixel>>16)&0xFF , (pixel>> 8)&0xFF , pixel &0xFF , 255);
  2606. case IMAGE_B8G8R8X8 : return Color( (pixel>>16)&0xFF , (pixel>> 8)&0xFF , pixel &0xFF , 255);
  2607. case IMAGE_R8G8B8X8 : return Color( (pixel )&0xFF , (pixel>> 8)&0xFF , (pixel>>16)&0xFF , 255);
  2608. case IMAGE_R10G10B10A2: return Color( (pixel>> 2)&0xFF , (pixel>>12)&0xFF , (pixel>>22)&0xFF , (pixel>>30)*255/3 );
  2609. case IMAGE_R8_SIGN : return Color(SByteToByte(pixel&0xFF), 0, 0 , 255 );
  2610. case IMAGE_R8G8_SIGN : return Color(SByteToByte(pixel&0xFF), SByteToByte((pixel>>8)&0xFF), 0 , 255 );
  2611. case IMAGE_R8G8B8A8_SIGN: return Color(SByteToByte(pixel&0xFF), SByteToByte((pixel>>8)&0xFF), SByteToByte((pixel>>16)&0xFF), SByteToByte(pixel>>24));
  2612. }
  2613. }
  2614. /******************************************************************************/
  2615. static UInt ColorToPixel(IMAGE_TYPE type, C Color &color) // convert color to pixel
  2616. {
  2617. switch(type)
  2618. {
  2619. case IMAGE_B8G8R8A8: return color.b | (color.g<<8) | (color.r<<16) | (color.a<<24);
  2620. case IMAGE_R8G8B8A8: return color.r | (color.g<<8) | (color.b<<16) | (color.a<<24);
  2621. case IMAGE_R8G8B8 : return color.r | (color.g<<8) | (color.b<<16);
  2622. case IMAGE_R8G8 : return color.r | (color.g<<8);
  2623. case IMAGE_R8 : return color.r;
  2624. case IMAGE_A8 : return color.a;
  2625. case IMAGE_L8 : return color.lum();
  2626. case IMAGE_L8A8 : return color.lum()|(color.a<<8);
  2627. case IMAGE_I8 : return color.r;
  2628. case IMAGE_I16 : return color.r<<8;
  2629. case IMAGE_I24 : return color.r<<16;
  2630. case IMAGE_I32 : return color.r<<24;
  2631. default : return 0;
  2632. case IMAGE_BC1 :
  2633. case IMAGE_BC2 :
  2634. case IMAGE_BC3 :
  2635. case IMAGE_BC7 :
  2636. case IMAGE_PVRTC1_2:
  2637. case IMAGE_PVRTC1_4:
  2638. case IMAGE_ETC1 :
  2639. case IMAGE_ETC2 :
  2640. case IMAGE_ETC2_A1 :
  2641. case IMAGE_ETC2_A8 : return color.r | (color.g<<8) | (color.b<<16) | (color.a<<24);
  2642. case IMAGE_B4G4R4X4: return ((color.r>>4)<< 8) | ((color.g>>4)<< 4) | (color.b>> 4) | 0xF000;
  2643. case IMAGE_B4G4R4A4: return ((color.r>>4)<< 8) | ((color.g>>4)<< 4) | (color.b>> 4) | ((color.a>>4)<<12);
  2644. case IMAGE_B5G5R5X1: return ((color.r>>3)<<10) | ((color.g>>3)<< 5) | (color.b>> 3) | 0x8000;
  2645. case IMAGE_B5G5R5A1: return ((color.r>>3)<<10) | ((color.g>>3)<< 5) | (color.b>> 3) | ((color.a>>7)<<15);
  2646. case IMAGE_B5G6R5 : return ((color.r>>3)<<11) | ((color.g>>2)<< 5) | (color.b>> 3);
  2647. case IMAGE_B8G8R8 : return ( color.r <<16) | ( color.g << 8) | (color.b );
  2648. case IMAGE_B8G8R8X8: return ( color.r <<16) | ( color.g << 8) | (color.b ) | 0xFF000000;
  2649. case IMAGE_R8G8B8X8: return ( color.r ) | ( color.g << 8) | (color.b<<16) | 0xFF000000;
  2650. case IMAGE_R8_SIGN : return (color.r>>1);
  2651. case IMAGE_R8G8_SIGN : return (color.r>>1) | ((color.g>>1)<<8);
  2652. case IMAGE_R8G8B8A8_SIGN: return (color.r>>1) | ((color.g>>1)<<8) | ((color.b>>1)<<16) | ((color.a>>1)<<24);
  2653. case IMAGE_R10G10B10A2: return (color.r*1023+127)/255 | (((color.g*1023+127)/255)<<10) | (((color.b*1023+127)/255)<<20) | (((color.a*3+127)/255)<<30);
  2654. }
  2655. }
  2656. static UInt ColorToPixel(IMAGE_TYPE type, IMAGE_TYPE hw_type, C Color &color) // convert color to pixel
  2657. {
  2658. if(type==hw_type)normal: return ColorToPixel(hw_type, color); // first check if types are the same, the most common case
  2659. Color c; switch(type) // however if we want 'type' but we've got 'hw_type' then we have to adjust the color we're going to set. This will prevent setting different R G B values for type=IMAGE_L8 when hw_type=IMAGE_R8G8B8A8
  2660. {
  2661. case IMAGE_R8G8B8:
  2662. case IMAGE_F16_3 :
  2663. case IMAGE_F32_3 : c.set(color.r, color.g, color.b, 255); break;
  2664. case IMAGE_R8G8 :
  2665. case IMAGE_F16_2:
  2666. case IMAGE_F32_2: c.set(color.r, color.g, 0, 255); break;
  2667. case IMAGE_R8 :
  2668. case IMAGE_I8 :
  2669. case IMAGE_I16:
  2670. case IMAGE_I24:
  2671. case IMAGE_I32:
  2672. case IMAGE_F16:
  2673. case IMAGE_F32: c.set(color.r, 0, 0, 255); break;
  2674. case IMAGE_A8 : c.set(0, 0, 0 , color.a); break;
  2675. case IMAGE_L8 : c.set(color.lum(), 255); break;
  2676. case IMAGE_L8A8: c.set(color.lum(), color.a); break;
  2677. default: goto normal;
  2678. }
  2679. return ColorToPixel(hw_type, c);
  2680. }
  2681. /******************************************************************************/
  2682. void Image::color (Int x, Int y, C Color &color) { if(highPrecision()) colorF (x, y, color.asVec4());else pixel (x, y, ColorToPixel(type(), hwType(), color ));}
  2683. void Image::color3D(Int x, Int y, Int z, C Color &color) { if(highPrecision()) color3DF(x, y, z, color.asVec4());else pixel3D(x, y, z, ColorToPixel(type(), hwType(), color ));}
  2684. Color Image::color (Int x, Int y )C {return compressed() ? decompress (x, y ) : highPrecision() ? Color(colorF (x, y )) : PixelToColor( hwType(), pixel (x, y ));}
  2685. Color Image::color3D(Int x, Int y, Int z )C {return compressed() ? decompress3D(x, y, z) : highPrecision() ? Color(color3DF(x, y, z )) : PixelToColor( hwType(), pixel3D(x, y, z));}
  2686. /******************************************************************************/
  2687. // COMPRESSION
  2688. /******************************************************************************/
  2689. Color Image::decompress(Int x, Int y)C
  2690. {
  2691. if(InRange(x, lw()) && InRange(y, lh()))switch(hwType()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  2692. {
  2693. case IMAGE_BC1 : return DecompressPixelBC1 (data() + (x>>2)* 8 + (y>>2)*pitch(), x&3, y&3);
  2694. case IMAGE_BC2 : return DecompressPixelBC2 (data() + (x>>2)*16 + (y>>2)*pitch(), x&3, y&3);
  2695. case IMAGE_BC3 : return DecompressPixelBC3 (data() + (x>>2)*16 + (y>>2)*pitch(), x&3, y&3);
  2696. case IMAGE_BC7 : return DecompressPixelBC7 (data() + (x>>2)*16 + (y>>2)*pitch(), x&3, y&3);
  2697. case IMAGE_ETC1 : return DecompressPixelETC1 (data() + (x>>2)* 8 + (y>>2)*pitch(), x&3, y&3);
  2698. case IMAGE_ETC2 : return DecompressPixelETC2 (data() + (x>>2)* 8 + (y>>2)*pitch(), x&3, y&3);
  2699. case IMAGE_ETC2_A1: return DecompressPixelETC2A1(data() + (x>>2)* 8 + (y>>2)*pitch(), x&3, y&3);
  2700. case IMAGE_ETC2_A8: return DecompressPixelETC2A8(data() + (x>>2)*16 + (y>>2)*pitch(), x&3, y&3);
  2701. }
  2702. return TRANSPARENT;
  2703. }
  2704. Color Image::decompress3D(Int x, Int y, Int z)C
  2705. {
  2706. if(InRange(x, lw()) && InRange(y, lh()) && InRange(z, ld()))switch(hwType()) // no need to check for "&& data()" because being "InRange(lockSize())" already guarantees 'data' being available
  2707. {
  2708. case IMAGE_BC1 : return DecompressPixelBC1 (data() + (x>>2)* 8 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2709. case IMAGE_BC2 : return DecompressPixelBC2 (data() + (x>>2)*16 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2710. case IMAGE_BC3 : return DecompressPixelBC3 (data() + (x>>2)*16 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2711. case IMAGE_BC7 : return DecompressPixelBC7 (data() + (x>>2)*16 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2712. case IMAGE_ETC1 : return DecompressPixelETC1 (data() + (x>>2)* 8 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2713. case IMAGE_ETC2 : return DecompressPixelETC2 (data() + (x>>2)* 8 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2714. case IMAGE_ETC2_A1: return DecompressPixelETC2A1(data() + (x>>2)* 8 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2715. case IMAGE_ETC2_A8: return DecompressPixelETC2A8(data() + (x>>2)*16 + (y>>2)*pitch() + z*pitch2(), x&3, y&3);
  2716. }
  2717. return TRANSPARENT;
  2718. }
  2719. /******************************************************************************/
  2720. // GATHER
  2721. /******************************************************************************/
  2722. void Image::gather(Flt *pixels, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets)C
  2723. {
  2724. switch(hwType())
  2725. {
  2726. case IMAGE_F32: FREPD(y, y_offsets)
  2727. {
  2728. C Flt *pixel=(Flt*)(data()+y_offset[y]*pitch());
  2729. FREPD(x, x_offsets)*pixels++=pixel[x_offset[x]];
  2730. }break;
  2731. case IMAGE_R8:
  2732. case IMAGE_A8:
  2733. case IMAGE_L8:
  2734. case IMAGE_I8: FREPD(y, y_offsets)
  2735. {
  2736. C Byte *pixel=data()+y_offset[y]*pitch();
  2737. FREPD(x, x_offsets)*pixels++=pixel[x_offset[x]]/Flt(0xFFu);
  2738. }break;
  2739. case IMAGE_I16: FREPD(y, y_offsets)
  2740. {
  2741. C U16 *pixel=(U16*)(data()+y_offset[y]*pitch());
  2742. FREPD(x, x_offsets)*pixels++=pixel[x_offset[x]]/Flt(0xFFFFu);
  2743. }break;
  2744. case IMAGE_I32: FREPD(y, y_offsets)
  2745. {
  2746. C U32 *pixel=(U32*)(data()+y_offset[y]*pitch());
  2747. FREPD(x, x_offsets)*pixels++=pixel[x_offset[x]]/Dbl(0xFFFFFFFFu); // Dbl required to get best precision
  2748. }break;
  2749. case IMAGE_B8G8R8A8: FREPD(y, y_offsets)
  2750. {
  2751. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2752. FREPD(x, x_offsets){C Color &src=color[x_offset[x]]; *pixels++=src.b/255.0f;}
  2753. }break;
  2754. case IMAGE_R8G8B8A8: FREPD(y, y_offsets)
  2755. {
  2756. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2757. FREPD(x, x_offsets){C Color &src=color[x_offset[x]]; *pixels++=src.r/255.0f;}
  2758. }break;
  2759. case IMAGE_R8G8B8: FREPD(y, y_offsets)
  2760. {
  2761. C VecB *color=(VecB*)(data()+y_offset[y]*pitch());
  2762. FREPD(x, x_offsets){C VecB &src=color[x_offset[x]]; *pixels++=src.x/255.0f;}
  2763. }break;
  2764. default:
  2765. {
  2766. FREPD(y, y_offsets)
  2767. FREPD(x, x_offsets)*pixels++=pixelF(x_offset[x], y_offset[y]);
  2768. }break;
  2769. }
  2770. }
  2771. /******************************************************************************/
  2772. void Image::gather(VecB *colors, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets)C
  2773. {
  2774. switch(hwType())
  2775. {
  2776. case IMAGE_B8G8R8A8: FREPD(y, y_offsets)
  2777. {
  2778. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2779. FREPD(x, x_offsets){C Color &src=color[x_offset[x]]; (colors++)->set(src.b, src.g, src.r);}
  2780. }break;
  2781. case IMAGE_R8G8B8A8: FREPD(y, y_offsets)
  2782. {
  2783. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2784. FREPD(x, x_offsets)*colors++=color[x_offset[x]].v3;
  2785. }break;
  2786. case IMAGE_R8G8B8: FREPD(y, y_offsets)
  2787. {
  2788. C VecB *color=(VecB*)(data()+y_offset[y]*pitch());
  2789. FREPD(x, x_offsets)*colors++=color[x_offset[x]];
  2790. }break;
  2791. default:
  2792. {
  2793. FREPD(y, y_offsets)
  2794. FREPD(x, x_offsets)*colors++=color(x_offset[x], y_offset[y]).v3;
  2795. }break;
  2796. }
  2797. }
  2798. /******************************************************************************/
  2799. void Image::gather(Color *colors, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets)C
  2800. {
  2801. switch(hwType())
  2802. {
  2803. case IMAGE_B8G8R8A8: FREPD(y, y_offsets)
  2804. {
  2805. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2806. FREPD(x, x_offsets){C Color &src=color[x_offset[x]]; (colors++)->set(src.b, src.g, src.r, src.a);}
  2807. }break;
  2808. case IMAGE_R8G8B8A8: FREPD(y, y_offsets)
  2809. {
  2810. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2811. FREPD(x, x_offsets)*colors++=color[x_offset[x]];
  2812. }break;
  2813. case IMAGE_R8G8B8: FREPD(y, y_offsets)
  2814. {
  2815. C VecB *color=(VecB*)(data()+y_offset[y]*pitch());
  2816. FREPD(x, x_offsets){C VecB &src=color[x_offset[x]]; (colors++)->set(src.x, src.y, src.z);}
  2817. }break;
  2818. default:
  2819. {
  2820. FREPD(y, y_offsets)
  2821. FREPD(x, x_offsets)*colors++=color(x_offset[x], y_offset[y]);
  2822. }break;
  2823. }
  2824. }
  2825. /******************************************************************************/
  2826. void Image::gather(Vec4 *colors, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets)C
  2827. {
  2828. switch(hwType())
  2829. {
  2830. case IMAGE_B8G8R8A8: FREPD(y, y_offsets)
  2831. {
  2832. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2833. FREPD(x, x_offsets){C Color &src=color[x_offset[x]]; (colors++)->set(src.b/255.0f, src.g/255.0f, src.r/255.0f, src.a/255.0f);}
  2834. }break;
  2835. case IMAGE_R8G8B8A8: FREPD(y, y_offsets)
  2836. {
  2837. C Color *color=(Color*)(data()+y_offset[y]*pitch());
  2838. FREPD(x, x_offsets){C Color &src=color[x_offset[x]]; (colors++)->set(src.r/255.0f, src.g/255.0f, src.b/255.0f, src.a/255.0f);}
  2839. }break;
  2840. case IMAGE_R8G8B8: FREPD(y, y_offsets)
  2841. {
  2842. C VecB *color=(VecB*)(data()+y_offset[y]*pitch());
  2843. FREPD(x, x_offsets){C VecB &src=color[x_offset[x]]; (colors++)->set(src.x/255.0f, src.y/255.0f, src.z/255.0f, 1);}
  2844. }break;
  2845. case IMAGE_F32_4: FREPD(y, y_offsets)
  2846. {
  2847. C Vec4 *color=(Vec4*)(data()+y_offset[y]*pitch());
  2848. FREPD(x, x_offsets)*colors++=color[x_offset[x]];
  2849. }break;
  2850. case IMAGE_F32_3: FREPD(y, y_offsets)
  2851. {
  2852. C Vec *color=(Vec*)(data()+y_offset[y]*pitch());
  2853. FREPD(x, x_offsets)(colors++)->set(color[x_offset[x]], 1);
  2854. }break;
  2855. default:
  2856. {
  2857. FREPD(y, y_offsets)
  2858. FREPD(x, x_offsets)*colors++=colorF(x_offset[x], y_offset[y]);
  2859. }break;
  2860. }
  2861. }
  2862. /******************************************************************************/
  2863. void Image::gather(Flt *pixels, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets, Int *z_offset, Int z_offsets)C
  2864. {
  2865. switch(hwType())
  2866. {
  2867. case IMAGE_F32: FREPD(z, z_offsets)
  2868. {
  2869. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2870. {
  2871. C Flt *pixel_y=(Flt*)(data_z+y_offset[y]*pitch());
  2872. FREPD(x, x_offsets)*pixels++=pixel_y[x_offset[x]];
  2873. }
  2874. }break;
  2875. case IMAGE_R8:
  2876. case IMAGE_A8:
  2877. case IMAGE_L8:
  2878. case IMAGE_I8: FREPD(z, z_offsets)
  2879. {
  2880. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2881. {
  2882. C Byte *pixel_y=data_z+y_offset[y]*pitch();
  2883. FREPD(x, x_offsets)*pixels++=pixel_y[x_offset[x]]/Flt(0xFFu);
  2884. }
  2885. }break;
  2886. case IMAGE_I16: FREPD(z, z_offsets)
  2887. {
  2888. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2889. {
  2890. C U16 *pixel_y=(U16*)(data_z+y_offset[y]*pitch());
  2891. FREPD(x, x_offsets)*pixels++=pixel_y[x_offset[x]]/Flt(0xFFFFu);
  2892. }
  2893. }break;
  2894. case IMAGE_I32: FREPD(z, z_offsets)
  2895. {
  2896. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2897. {
  2898. C U32 *pixel_y=(U32*)(data_z+y_offset[y]*pitch());
  2899. FREPD(x, x_offsets)*pixels++=pixel_y[x_offset[x]]/Dbl(0xFFFFFFFFu); // Dbl required to get best precision
  2900. }
  2901. }break;
  2902. case IMAGE_B8G8R8A8: FREPD(z, z_offsets)
  2903. {
  2904. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2905. {
  2906. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  2907. FREPD(x, x_offsets){C Color &src=color_y[x_offset[x]]; *pixels++=src.b/255.0f;}
  2908. }
  2909. }break;
  2910. case IMAGE_R8G8B8A8: FREPD(z, z_offsets)
  2911. {
  2912. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2913. {
  2914. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  2915. FREPD(x, x_offsets){C Color &src=color_y[x_offset[x]]; *pixels++=src.r/255.0f;}
  2916. }
  2917. }break;
  2918. case IMAGE_R8G8B8: FREPD(z, z_offsets)
  2919. {
  2920. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2921. {
  2922. C VecB *color_y=(VecB*)(data_z+y_offset[y]*pitch());
  2923. FREPD(x, x_offsets){C VecB &src=color_y[x_offset[x]]; *pixels++=src.x/255.0f;}
  2924. }
  2925. }break;
  2926. default:
  2927. {
  2928. FREPD(z, z_offsets)
  2929. FREPD(y, y_offsets)
  2930. FREPD(x, x_offsets)*pixels++=pixel3DF(x_offset[x], y_offset[y], z_offset[z]);
  2931. }break;
  2932. }
  2933. }
  2934. /******************************************************************************/
  2935. void Image::gather(VecB *colors, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets, Int *z_offset, Int z_offsets)C
  2936. {
  2937. switch(hwType())
  2938. {
  2939. case IMAGE_B8G8R8A8: FREPD(z, z_offsets)
  2940. {
  2941. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2942. {
  2943. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  2944. FREPD(x, x_offsets){C Color &src=color_y[x_offset[x]]; (colors++)->set(src.b, src.g, src.r);}
  2945. }
  2946. }break;
  2947. case IMAGE_R8G8B8A8: FREPD(z, z_offsets)
  2948. {
  2949. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2950. {
  2951. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  2952. FREPD(x, x_offsets)*colors++=color_y[x_offset[x]].v3;
  2953. }
  2954. }break;
  2955. case IMAGE_R8G8B8: FREPD(z, z_offsets)
  2956. {
  2957. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2958. {
  2959. C VecB *color_y=(VecB*)(data_z+y_offset[y]*pitch());
  2960. FREPD(x, x_offsets)*colors++=color_y[x_offset[x]];
  2961. }
  2962. }break;
  2963. default:
  2964. {
  2965. FREPD(z, z_offsets)
  2966. FREPD(y, y_offsets)
  2967. FREPD(x, x_offsets)*colors++=color3D(x_offset[x], y_offset[y], z_offset[z]).v3;
  2968. }break;
  2969. }
  2970. }
  2971. /******************************************************************************/
  2972. void Image::gather(Color *colors, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets, Int *z_offset, Int z_offsets)C
  2973. {
  2974. switch(hwType())
  2975. {
  2976. case IMAGE_B8G8R8A8: FREPD(z, z_offsets)
  2977. {
  2978. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2979. {
  2980. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  2981. FREPD(x, x_offsets){C Color &src=color_y[x_offset[x]]; (colors++)->set(src.b, src.g, src.r, src.a);}
  2982. }
  2983. }break;
  2984. case IMAGE_R8G8B8A8: FREPD(z, z_offsets)
  2985. {
  2986. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2987. {
  2988. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  2989. FREPD(x, x_offsets)*colors++=color_y[x_offset[x]];
  2990. }
  2991. }break;
  2992. case IMAGE_R8G8B8: FREPD(z, z_offsets)
  2993. {
  2994. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  2995. {
  2996. C VecB *color_y=(VecB*)(data_z+y_offset[y]*pitch());
  2997. FREPD(x, x_offsets){C VecB &src=color_y[x_offset[x]]; (colors++)->set(src.x, src.y, src.z);}
  2998. }
  2999. }break;
  3000. default:
  3001. {
  3002. FREPD(z, z_offsets)
  3003. FREPD(y, y_offsets)
  3004. FREPD(x, x_offsets)*colors++=color3D(x_offset[x], y_offset[y], z_offset[z]);
  3005. }break;
  3006. }
  3007. }
  3008. /******************************************************************************/
  3009. void Image::gather(Vec4 *colors, Int *x_offset, Int x_offsets, Int *y_offset, Int y_offsets, Int *z_offset, Int z_offsets)C
  3010. {
  3011. switch(hwType())
  3012. {
  3013. case IMAGE_B8G8R8A8: FREPD(z, z_offsets)
  3014. {
  3015. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  3016. {
  3017. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  3018. FREPD(x, x_offsets){C Color &src=color_y[x_offset[x]]; (colors++)->set(src.b/255.0f, src.g/255.0f, src.r/255.0f, src.a/255.0f);}
  3019. }
  3020. }break;
  3021. case IMAGE_R8G8B8A8: FREPD(z, z_offsets)
  3022. {
  3023. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  3024. {
  3025. C Color *color_y=(Color*)(data_z+y_offset[y]*pitch());
  3026. FREPD(x, x_offsets){C Color &src=color_y[x_offset[x]]; (colors++)->set(src.r/255.0f, src.g/255.0f, src.b/255.0f, src.a/255.0f);}
  3027. }
  3028. }break;
  3029. case IMAGE_R8G8B8: FREPD(z, z_offsets)
  3030. {
  3031. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  3032. {
  3033. C VecB *color_y=(VecB*)(data_z+y_offset[y]*pitch());
  3034. FREPD(x, x_offsets){C VecB &src=color_y[x_offset[x]]; (colors++)->set(src.x/255.0f, src.y/255.0f, src.z/255.0f, 1);}
  3035. }
  3036. }break;
  3037. case IMAGE_F32_4: FREPD(z, z_offsets)
  3038. {
  3039. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  3040. {
  3041. C Vec4 *color_y=(Vec4*)(data_z+y_offset[y]*pitch());
  3042. FREPD(x, x_offsets)*colors++=color_y[x_offset[x]];
  3043. }
  3044. }break;
  3045. case IMAGE_F32_3: FREPD(z, z_offsets)
  3046. {
  3047. C Byte *data_z=data()+z_offset[z]*pitch2(); FREPD(y, y_offsets)
  3048. {
  3049. C Vec *color_y=(Vec*)(data_z+y_offset[y]*pitch());
  3050. FREPD(x, x_offsets)(colors++)->set(color_y[x_offset[x]], 1);
  3051. }
  3052. }break;
  3053. default:
  3054. {
  3055. FREPD(z, z_offsets)
  3056. FREPD(y, y_offsets)
  3057. FREPD(x, x_offsets)*colors++=color3DF(x_offset[x], y_offset[y], z_offset[z]);
  3058. }break;
  3059. }
  3060. }
  3061. /******************************************************************************/
  3062. static Bool NeedMultiChannel(IMAGE_TYPE src, IMAGE_TYPE dest)
  3063. {
  3064. return ImageTI[src].channels>1 || src!=dest;
  3065. }
  3066. static INLINE void StorePixel(Image &image, Byte* &dest_data_y, Int x, Int y, Int z, Flt pixel)
  3067. {
  3068. switch(image.hwType())
  3069. {
  3070. case IMAGE_I8 :
  3071. case IMAGE_R8 :
  3072. case IMAGE_L8 :
  3073. case IMAGE_A8 : *dest_data_y++=FltToByte(pixel); break;
  3074. case IMAGE_F32: *(Flt*)dest_data_y=pixel; dest_data_y+=SIZE(Flt); break;
  3075. default : image.pixel3DF(x, y, z, pixel); break;
  3076. }
  3077. }
  3078. static INLINE void StoreColor(Image &image, Byte* &dest_data_y, Int x, Int y, Int z, C Vec4 &color)
  3079. {
  3080. if(image.type()==image.hwType())switch(image.hwType()) // check 'type' too in case we have to perform color adjustment
  3081. {
  3082. case IMAGE_I8 :
  3083. case IMAGE_R8 : *dest_data_y++=FltToByte(color.x); return;
  3084. case IMAGE_B8G8R8A8: ((VecB4*)dest_data_y)->set(FltToByte(color.z), FltToByte(color.y), FltToByte(color.x), FltToByte(color.w)); dest_data_y+=4; return;
  3085. case IMAGE_R8G8B8A8: *(Color*)dest_data_y=color; dest_data_y+=4; return;
  3086. case IMAGE_R8G8B8 : dest_data_y[0]=FltToByte(color.x); dest_data_y[1]=FltToByte(color.y); dest_data_y[2]=FltToByte(color.z); dest_data_y+=3; return;
  3087. case IMAGE_L8 : *dest_data_y++=FltToByte(color.xyz.max()); return;
  3088. case IMAGE_L8A8 : *dest_data_y++=FltToByte(color.xyz.max()); // !! no break/return on purpose so we can set Alpha channel below !!
  3089. case IMAGE_A8 : *dest_data_y++=FltToByte(color.w); return;
  3090. }
  3091. image.color3DF(x, y, z, color);
  3092. }
  3093. Bool Image::copySoft(Image &dest, FILTER_TYPE filter, Bool clamp, Bool alpha_weight, Bool keep_edges, Flt sharp_smooth)C // this does not support compressed images
  3094. {
  3095. if(this==&dest )return true;
  3096. if(cube()!=dest.cube())return false;
  3097. REPD(f, faces())
  3098. {
  3099. if(! T.lockRead( 0, (DIR_ENUM)f)) return false;
  3100. if(!dest.lock(LOCK_WRITE, 0, (DIR_ENUM)f)){T.unlock(); return false;}
  3101. if(T.size3()==dest.size3()) // no resize
  3102. {
  3103. if(T.hwType()==dest.hwType() // no retype
  3104. && T. type()==dest. type()) // check 'type' too in case we have to perform color adjustment
  3105. {
  3106. Int valid_blocks_y=ImageBlocksY(T.w(), T.h(), 0, T.hwType()); // use "w(), h()" instead of "hwW(), hwH()" to copy only valid pixels
  3107. REPD(z, T.d())
  3108. {
  3109. C Byte *s=T .data() + z*T .pitch2();
  3110. Byte *d=dest.data() + z*dest.pitch2();
  3111. if(T.pitch()==dest.pitch() )CopyFast(d, s, Min(T.pitch2(), dest.pitch2()));
  3112. else REPD(y, valid_blocks_y)CopyFast(d + y*dest.pitch(), s + y*T.pitch(), Min(T.pitch(), dest.pitch()));
  3113. // TODO: we could zero remaining data to avoid garbage
  3114. }
  3115. }else // retype
  3116. {
  3117. if(T .hwType()==IMAGE_R8G8B8
  3118. && dest.hwType()==IMAGE_R8G8B8A8 // very common case for importing images
  3119. && dest. type()==IMAGE_R8G8B8A8) // check 'type' too in case we have to perform color adjustment
  3120. {
  3121. REPD(z, T.d())
  3122. REPD(y, T.h())
  3123. {
  3124. C VecB *s=(VecB *)(T .data() + y*T .pitch() + z*T .pitch2());
  3125. VecB4 *d=(VecB4*)(dest.data() + y*dest.pitch() + z*dest.pitch2());
  3126. REPD(x, T.w()){(d++)->set(s->x, s->y, s->z, 255); s++;}
  3127. }
  3128. }else
  3129. if(T .hwType()==IMAGE_R8G8B8
  3130. && dest.hwType()==IMAGE_B8G8R8A8 // very common case for importing images
  3131. && dest. type()==IMAGE_B8G8R8A8) // check 'type' too in case we have to perform color adjustment
  3132. {
  3133. REPD(z, T.d())
  3134. REPD(y, T.h())
  3135. {
  3136. C VecB *s=(VecB *)(T .data() + y*T .pitch() + z*T .pitch2());
  3137. VecB4 *d=(VecB4*)(dest.data() + y*dest.pitch() + z*dest.pitch2());
  3138. REPD(x, T.w()){(d++)->set(s->z, s->y, s->x, 255); s++;}
  3139. }
  3140. }else
  3141. if(T .highPrecision()
  3142. && dest.highPrecision()) // high precision requires FP
  3143. {
  3144. REPD(z, T.d())
  3145. REPD(y, T.h())
  3146. REPD(x, T.w())dest.color3DF(x, y, z, T.color3DF(x, y, z));
  3147. }else
  3148. {
  3149. REPD(z, T.d())
  3150. REPD(y, T.h())
  3151. REPD(x, T.w())dest.color3D(x, y, z, T.color3D(x, y, z));
  3152. }
  3153. }
  3154. }else
  3155. if(filter==FILTER_NO_STRETCH)
  3156. {
  3157. if(dest.hwType()==IMAGE_R8G8B8A8 // common case for encoding BC7
  3158. && dest. type()==IMAGE_R8G8B8A8) // check 'type' too in case we have to perform color adjustment
  3159. {
  3160. Int x_blocks=dest.w()/4,
  3161. y_blocks=dest.h()/4;
  3162. REPD(z, dest.d())
  3163. {
  3164. Byte *dest_z=dest.data() + z*dest.pitch2();
  3165. Int zo =(clamp ? Min(z, T.d()-1) : z%T.d());
  3166. REPD(by, y_blocks)
  3167. {
  3168. Int py=by*4, yo[4]; // pixel and offset
  3169. REPAO(yo)=(clamp ? Min(py+i, T.h()-1) : (py+i)%T.h());
  3170. Byte *dest_y=dest_z + py*dest.pitch();
  3171. REPD(bx, x_blocks)
  3172. {
  3173. Int px=bx*4, xo[4]; // pixel and offset
  3174. REPAO(xo)=(clamp ? Min(px+i, T.w()-1) : (px+i)%T.w());
  3175. Color col[4][4];
  3176. T.gather(col[0], xo, Elms(xo), yo, Elms(yo), &zo, 1);
  3177. Byte *dest_x=dest_y + px*SIZE(Color);
  3178. REP(4)CopyFast(dest_x + i*dest.pitch(), col[i], SIZE(Color)*4);
  3179. }
  3180. }
  3181. // process partial blocks
  3182. x_blocks*=4;
  3183. y_blocks*=4;
  3184. // process right side (excluding shared corner)
  3185. if(x_blocks!=dest.w())
  3186. for(Int y= 0; y<y_blocks; y++)
  3187. for(Int x=x_blocks; x<dest.w(); x++)dest.color3D(x, y, z, clamp ? T.color3D(Min(x, w()-1), Min(y, h()-1), zo) : T.color3D(x%w(), y%h(), zo));
  3188. // process bottom side (including shared corner)
  3189. //if(y_blocks!=dest.h()) not needed since we're starting with Y's and this will be checked on its own
  3190. for(Int y=y_blocks; y<dest.h(); y++)
  3191. for(Int x= 0; x<dest.w(); x++)dest.color3D(x, y, z, clamp ? T.color3D(Min(x, w()-1), Min(y, h()-1), zo) : T.color3D(x%w(), y%h(), zo));
  3192. }
  3193. }else
  3194. if(T .highPrecision()
  3195. && dest.highPrecision()) // high precision requires FP
  3196. {
  3197. REPD(z, dest.d())
  3198. REPD(y, dest.h())
  3199. REPD(x, dest.w())dest.color3DF(x, y, z, clamp ? T.color3DF(Min(x, w()-1), Min(y, h()-1), Min(z, d()-1)) : T.color3DF(x%w(), y%h(), z%d()));
  3200. }else
  3201. {
  3202. REPD(z, dest.d())
  3203. REPD(y, dest.h())
  3204. REPD(x, dest.w())dest.color3D(x, y, z, clamp ? T.color3D(Min(x, w()-1), Min(y, h()-1), Min(z, d()-1)) : T.color3D(x%w(), y%h(), z%d()));
  3205. }
  3206. }else // resize
  3207. {
  3208. if(!ImageTI[hwType()].a)alpha_weight=false; // disable 'alpha_weight' if the source doesn't have it
  3209. Bool t_high_prec=T.highPrecision(), high_prec=(t_high_prec || dest.highPrecision());
  3210. // check for optimized downscale
  3211. if(dest.w()==Max(1, T.w()>>1)
  3212. && dest.h()==Max(1, T.h()>>1)
  3213. && dest.d()==Max(1, T.d()>>1) // 2x downsample
  3214. && !keep_edges
  3215. && (Equal(sharp_smooth, 1) || filter==FILTER_NONE)
  3216. )
  3217. {
  3218. if(T.d()<=1) // 2D
  3219. {
  3220. switch(filter)
  3221. {
  3222. case FILTER_NONE: REPD(y, dest.h())
  3223. {
  3224. Int yc=y*2;
  3225. if(high_prec)REPD(x, dest.w())dest.colorF(x, y, colorF(x*2, yc));
  3226. else REPD(x, dest.w())dest.color (x, y, color (x*2, yc));
  3227. }goto finish;
  3228. case FILTER_LINEAR: REPD(y, dest.h())
  3229. {
  3230. Int yc[2]; yc[0]=y*2; yc[1]=(clamp ? Min(yc[0]+1, h()-1) : (yc[0]+1)%h()); // yc[0] is always OK
  3231. REPD(x, dest.w())
  3232. {
  3233. Int xc[2]; xc[0]=x*2; xc[1]=(clamp ? Min(xc[0]+1, w()-1) : (xc[0]+1)%w()); // xc[0] is always OK
  3234. if(high_prec)
  3235. {
  3236. Vec4 col, c[2][2]; gather(&c[0][0], xc, Elms(xc), yc, Elms(yc)); // [y][x]
  3237. if(!alpha_weight)
  3238. {
  3239. col.w=Avg(c[0][0].w, c[0][1].w, c[1][0].w, c[1][1].w);
  3240. linear_rgb_f:
  3241. col.x=Avg(c[0][0].x, c[0][1].x, c[1][0].x, c[1][1].x);
  3242. col.y=Avg(c[0][0].y, c[0][1].y, c[1][0].y, c[1][1].y);
  3243. col.z=Avg(c[0][0].z, c[0][1].z, c[1][0].z, c[1][1].z);
  3244. }else
  3245. {
  3246. Flt a=c[0][0].w+c[0][1].w+c[1][0].w+c[1][1].w;
  3247. if(!a){col.w=0; goto linear_rgb_f;}
  3248. col.w=a/4;
  3249. col.x=(c[0][0].x*c[0][0].w + c[0][1].x*c[0][1].w + c[1][0].x*c[1][0].w + c[1][1].x*c[1][1].w)/a;
  3250. col.y=(c[0][0].y*c[0][0].w + c[0][1].y*c[0][1].w + c[1][0].y*c[1][0].w + c[1][1].y*c[1][1].w)/a;
  3251. col.z=(c[0][0].z*c[0][0].w + c[0][1].z*c[0][1].w + c[1][0].z*c[1][0].w + c[1][1].z*c[1][1].w)/a;
  3252. }
  3253. dest.colorF(x, y, col);
  3254. }else
  3255. {
  3256. Color col, c[2][2]; gather(&c[0][0], xc, Elms(xc), yc, Elms(yc)); // [y][x]
  3257. if(!alpha_weight)
  3258. {
  3259. col.a=((c[0][0].a+c[0][1].a+c[1][0].a+c[1][1].a+2)>>2);
  3260. linear_rgb:
  3261. col.r=((c[0][0].r+c[0][1].r+c[1][0].r+c[1][1].r+2)>>2);
  3262. col.g=((c[0][0].g+c[0][1].g+c[1][0].g+c[1][1].g+2)>>2);
  3263. col.b=((c[0][0].b+c[0][1].b+c[1][0].b+c[1][1].b+2)>>2);
  3264. }else
  3265. {
  3266. UInt a=c[0][0].a+c[0][1].a+c[1][0].a+c[1][1].a;
  3267. if( !a){col.a=0; goto linear_rgb;}
  3268. col.a=((a+2)>>2); UInt a_2=a>>1;
  3269. col.r=(c[0][0].r*c[0][0].a + c[0][1].r*c[0][1].a + c[1][0].r*c[1][0].a + c[1][1].r*c[1][1].a + a_2)/a;
  3270. col.g=(c[0][0].g*c[0][0].a + c[0][1].g*c[0][1].a + c[1][0].g*c[1][0].a + c[1][1].g*c[1][1].a + a_2)/a;
  3271. col.b=(c[0][0].b*c[0][0].a + c[0][1].b*c[0][1].a + c[1][0].b*c[1][0].a + c[1][1].b*c[1][1].a + a_2)/a;
  3272. }
  3273. dest.color(x, y, col);
  3274. }
  3275. }
  3276. }goto finish;
  3277. case FILTER_BEST:
  3278. case FILTER_CUBIC_FAST_SHARP: ASSERT(FILTER_DOWN==FILTER_CUBIC_FAST_SHARP);
  3279. {
  3280. if(!high_prec)
  3281. {
  3282. REPD(y, dest.h())
  3283. {
  3284. Int yc[8]; yc[3]=y*2; // 'y[3]' is always OK
  3285. if(clamp){yc[0]=Max(yc[3]-3, 0 ); yc[1]=Max(yc[3]-2, 0 ); yc[2]=Max(yc[3]-1, 0 ); yc[4]=Min(yc[3]+1, h()-1); yc[5]=Min(yc[3]+2, h()-1); yc[6]=Min(yc[3]+3, h()-1); yc[7]=Min(yc[3]+4, h()-1);}
  3286. else {yc[0]=Mod(yc[3]-3, h()); yc[1]=Mod(yc[3]-2, h()); yc[2]=Mod(yc[3]-1, h()); yc[4]= (yc[3]+1)%h() ; yc[5]= (yc[3]+2)%h() ; yc[6]= (yc[3]+3)%h() ; yc[7]= (yc[3]+4)%h() ;}
  3287. REPD(x, dest.w())
  3288. {
  3289. Int xc[8]; xc[3]=x*2; // 'x[3]' is always OK
  3290. if(clamp){xc[0]=Max(xc[3]-3, 0 ); xc[1]=Max(xc[3]-2, 0 ); xc[2]=Max(xc[3]-1, 0 ); xc[4]=Min(xc[3]+1, w()-1); xc[5]=Min(xc[3]+2, w()-1); xc[6]=Min(xc[3]+3, w()-1); xc[7]=Min(xc[3]+4, w()-1);}
  3291. else {xc[0]=Mod(xc[3]-3, w()); xc[1]=Mod(xc[3]-2, w()); xc[2]=Mod(xc[3]-1, w()); xc[4]= (xc[3]+1)%w() ; xc[5]= (xc[3]+2)%w() ; xc[6]= (xc[3]+3)%w() ; xc[7]= (xc[3]+4)%w() ;}
  3292. Color col, c[8][8]; // [y][x]
  3293. #if 1 // read 8x8
  3294. gather(&c[0][0], xc, Elms(xc), yc, Elms(yc));
  3295. #else // read 4x1, 8x6, 4x1, performance is the same
  3296. gather(&c[0][2], xc+2, Elms(xc)-4, yc , 1 ); // top
  3297. gather(&c[1][0], xc , Elms(xc) , yc+1, Elms(yc)-2); // center
  3298. gather(&c[7][2], xc+2, Elms(xc)-4, yc+7, 1 ); // bottom
  3299. #endif
  3300. if(!alpha_weight)
  3301. {
  3302. col.a=Mid((/*c[0][0].a*CW8[0][0] + c[0][1].a*CW8[0][1]*/+ c[0][2].a*CW8[0][2] + c[0][3].a*CW8[0][3] + c[0][4].a*CW8[0][4] + c[0][5].a*CW8[0][5] +/*c[0][6].a*CW8[0][6] + c[0][7].a*CW8[0][7]*/
  3303. /*+ c[1][0].a*CW8[1][0]*/+ c[1][1].a*CW8[1][1] + c[1][2].a*CW8[1][2] + c[1][3].a*CW8[1][3] + c[1][4].a*CW8[1][4] + c[1][5].a*CW8[1][5] + c[1][6].a*CW8[1][6] +/*c[1][7].a*CW8[1][7]*/
  3304. + c[2][0].a*CW8[2][0] + c[2][1].a*CW8[2][1] + c[2][2].a*CW8[2][2] + c[2][3].a*CW8[2][3] + c[2][4].a*CW8[2][4] + c[2][5].a*CW8[2][5] + c[2][6].a*CW8[2][6] + c[2][7].a*CW8[2][7]
  3305. + c[3][0].a*CW8[3][0] + c[3][1].a*CW8[3][1] + c[3][2].a*CW8[3][2] + c[3][3].a*CW8[3][3] + c[3][4].a*CW8[3][4] + c[3][5].a*CW8[3][5] + c[3][6].a*CW8[3][6] + c[3][7].a*CW8[3][7]
  3306. + c[4][0].a*CW8[4][0] + c[4][1].a*CW8[4][1] + c[4][2].a*CW8[4][2] + c[4][3].a*CW8[4][3] + c[4][4].a*CW8[4][4] + c[4][5].a*CW8[4][5] + c[4][6].a*CW8[4][6] + c[4][7].a*CW8[4][7]
  3307. + c[5][0].a*CW8[5][0] + c[5][1].a*CW8[5][1] + c[5][2].a*CW8[5][2] + c[5][3].a*CW8[5][3] + c[5][4].a*CW8[5][4] + c[5][5].a*CW8[5][5] + c[5][6].a*CW8[5][6] + c[5][7].a*CW8[5][7]
  3308. /*+ c[6][0].a*CW8[6][0]*/+ c[6][1].a*CW8[6][1] + c[6][2].a*CW8[6][2] + c[6][3].a*CW8[6][3] + c[6][4].a*CW8[6][4] + c[6][5].a*CW8[6][5] + c[6][6].a*CW8[6][6] +/*c[6][7].a*CW8[6][7]*/
  3309. /*+ c[7][0].a*CW8[7][0] + c[7][1].a*CW8[7][1]*/+ c[7][2].a*CW8[7][2] + c[7][3].a*CW8[7][3] + c[7][4].a*CW8[7][4] + c[7][5].a*CW8[7][5] +/*c[7][6].a*CW8[7][6] + c[7][7].a*CW8[7][7]*/ + CW8Sum/2)/CW8Sum, 0, 255);
  3310. cubic_sharp_rgb:
  3311. col.r=Mid((/*c[0][0].r*CW8[0][0] + c[0][1].r*CW8[0][1]*/+ c[0][2].r*CW8[0][2] + c[0][3].r*CW8[0][3] + c[0][4].r*CW8[0][4] + c[0][5].r*CW8[0][5] +/*c[0][6].r*CW8[0][6] + c[0][7].r*CW8[0][7]*/
  3312. /*+ c[1][0].r*CW8[1][0]*/+ c[1][1].r*CW8[1][1] + c[1][2].r*CW8[1][2] + c[1][3].r*CW8[1][3] + c[1][4].r*CW8[1][4] + c[1][5].r*CW8[1][5] + c[1][6].r*CW8[1][6] +/*c[1][7].r*CW8[1][7]*/
  3313. + c[2][0].r*CW8[2][0] + c[2][1].r*CW8[2][1] + c[2][2].r*CW8[2][2] + c[2][3].r*CW8[2][3] + c[2][4].r*CW8[2][4] + c[2][5].r*CW8[2][5] + c[2][6].r*CW8[2][6] + c[2][7].r*CW8[2][7]
  3314. + c[3][0].r*CW8[3][0] + c[3][1].r*CW8[3][1] + c[3][2].r*CW8[3][2] + c[3][3].r*CW8[3][3] + c[3][4].r*CW8[3][4] + c[3][5].r*CW8[3][5] + c[3][6].r*CW8[3][6] + c[3][7].r*CW8[3][7]
  3315. + c[4][0].r*CW8[4][0] + c[4][1].r*CW8[4][1] + c[4][2].r*CW8[4][2] + c[4][3].r*CW8[4][3] + c[4][4].r*CW8[4][4] + c[4][5].r*CW8[4][5] + c[4][6].r*CW8[4][6] + c[4][7].r*CW8[4][7]
  3316. + c[5][0].r*CW8[5][0] + c[5][1].r*CW8[5][1] + c[5][2].r*CW8[5][2] + c[5][3].r*CW8[5][3] + c[5][4].r*CW8[5][4] + c[5][5].r*CW8[5][5] + c[5][6].r*CW8[5][6] + c[5][7].r*CW8[5][7]
  3317. /*+ c[6][0].r*CW8[6][0]*/+ c[6][1].r*CW8[6][1] + c[6][2].r*CW8[6][2] + c[6][3].r*CW8[6][3] + c[6][4].r*CW8[6][4] + c[6][5].r*CW8[6][5] + c[6][6].r*CW8[6][6] +/*c[6][7].r*CW8[6][7]*/
  3318. /*+ c[7][0].r*CW8[7][0] + c[7][1].r*CW8[7][1]*/+ c[7][2].r*CW8[7][2] + c[7][3].r*CW8[7][3] + c[7][4].r*CW8[7][4] + c[7][5].r*CW8[7][5] +/*c[7][6].r*CW8[7][6] + c[7][7].r*CW8[7][7]*/ + CW8Sum/2)/CW8Sum, 0, 255);
  3319. col.g=Mid((/*c[0][0].g*CW8[0][0] + c[0][1].g*CW8[0][1]*/+ c[0][2].g*CW8[0][2] + c[0][3].g*CW8[0][3] + c[0][4].g*CW8[0][4] + c[0][5].g*CW8[0][5] +/*c[0][6].g*CW8[0][6] + c[0][7].g*CW8[0][7]*/
  3320. /*+ c[1][0].g*CW8[1][0]*/+ c[1][1].g*CW8[1][1] + c[1][2].g*CW8[1][2] + c[1][3].g*CW8[1][3] + c[1][4].g*CW8[1][4] + c[1][5].g*CW8[1][5] + c[1][6].g*CW8[1][6] +/*c[1][7].g*CW8[1][7]*/
  3321. + c[2][0].g*CW8[2][0] + c[2][1].g*CW8[2][1] + c[2][2].g*CW8[2][2] + c[2][3].g*CW8[2][3] + c[2][4].g*CW8[2][4] + c[2][5].g*CW8[2][5] + c[2][6].g*CW8[2][6] + c[2][7].g*CW8[2][7]
  3322. + c[3][0].g*CW8[3][0] + c[3][1].g*CW8[3][1] + c[3][2].g*CW8[3][2] + c[3][3].g*CW8[3][3] + c[3][4].g*CW8[3][4] + c[3][5].g*CW8[3][5] + c[3][6].g*CW8[3][6] + c[3][7].g*CW8[3][7]
  3323. + c[4][0].g*CW8[4][0] + c[4][1].g*CW8[4][1] + c[4][2].g*CW8[4][2] + c[4][3].g*CW8[4][3] + c[4][4].g*CW8[4][4] + c[4][5].g*CW8[4][5] + c[4][6].g*CW8[4][6] + c[4][7].g*CW8[4][7]
  3324. + c[5][0].g*CW8[5][0] + c[5][1].g*CW8[5][1] + c[5][2].g*CW8[5][2] + c[5][3].g*CW8[5][3] + c[5][4].g*CW8[5][4] + c[5][5].g*CW8[5][5] + c[5][6].g*CW8[5][6] + c[5][7].g*CW8[5][7]
  3325. /*+ c[6][0].g*CW8[6][0]*/+ c[6][1].g*CW8[6][1] + c[6][2].g*CW8[6][2] + c[6][3].g*CW8[6][3] + c[6][4].g*CW8[6][4] + c[6][5].g*CW8[6][5] + c[6][6].g*CW8[6][6] +/*c[6][7].g*CW8[6][7]*/
  3326. /*+ c[7][0].g*CW8[7][0] + c[7][1].g*CW8[7][1]*/+ c[7][2].g*CW8[7][2] + c[7][3].g*CW8[7][3] + c[7][4].g*CW8[7][4] + c[7][5].g*CW8[7][5] +/*c[7][6].g*CW8[7][6] + c[7][7].g*CW8[7][7]*/ + CW8Sum/2)/CW8Sum, 0, 255);
  3327. col.b=Mid((/*c[0][0].b*CW8[0][0] + c[0][1].b*CW8[0][1]*/+ c[0][2].b*CW8[0][2] + c[0][3].b*CW8[0][3] + c[0][4].b*CW8[0][4] + c[0][5].b*CW8[0][5] +/*c[0][6].b*CW8[0][6] + c[0][7].b*CW8[0][7]*/
  3328. /*+ c[1][0].b*CW8[1][0]*/+ c[1][1].b*CW8[1][1] + c[1][2].b*CW8[1][2] + c[1][3].b*CW8[1][3] + c[1][4].b*CW8[1][4] + c[1][5].b*CW8[1][5] + c[1][6].b*CW8[1][6] +/*c[1][7].b*CW8[1][7]*/
  3329. + c[2][0].b*CW8[2][0] + c[2][1].b*CW8[2][1] + c[2][2].b*CW8[2][2] + c[2][3].b*CW8[2][3] + c[2][4].b*CW8[2][4] + c[2][5].b*CW8[2][5] + c[2][6].b*CW8[2][6] + c[2][7].b*CW8[2][7]
  3330. + c[3][0].b*CW8[3][0] + c[3][1].b*CW8[3][1] + c[3][2].b*CW8[3][2] + c[3][3].b*CW8[3][3] + c[3][4].b*CW8[3][4] + c[3][5].b*CW8[3][5] + c[3][6].b*CW8[3][6] + c[3][7].b*CW8[3][7]
  3331. + c[4][0].b*CW8[4][0] + c[4][1].b*CW8[4][1] + c[4][2].b*CW8[4][2] + c[4][3].b*CW8[4][3] + c[4][4].b*CW8[4][4] + c[4][5].b*CW8[4][5] + c[4][6].b*CW8[4][6] + c[4][7].b*CW8[4][7]
  3332. + c[5][0].b*CW8[5][0] + c[5][1].b*CW8[5][1] + c[5][2].b*CW8[5][2] + c[5][3].b*CW8[5][3] + c[5][4].b*CW8[5][4] + c[5][5].b*CW8[5][5] + c[5][6].b*CW8[5][6] + c[5][7].b*CW8[5][7]
  3333. /*+ c[6][0].b*CW8[6][0]*/+ c[6][1].b*CW8[6][1] + c[6][2].b*CW8[6][2] + c[6][3].b*CW8[6][3] + c[6][4].b*CW8[6][4] + c[6][5].b*CW8[6][5] + c[6][6].b*CW8[6][6] +/*c[6][7].b*CW8[6][7]*/
  3334. /*+ c[7][0].b*CW8[7][0] + c[7][1].b*CW8[7][1]*/+ c[7][2].b*CW8[7][2] + c[7][3].b*CW8[7][3] + c[7][4].b*CW8[7][4] + c[7][5].b*CW8[7][5] +/*c[7][6].b*CW8[7][6] + c[7][7].b*CW8[7][7]*/ + CW8Sum/2)/CW8Sum, 0, 255);
  3335. }else
  3336. {
  3337. Int w[8][8]={{/*CWA8[0][0]*c[0][0].a*/0,/*CWA8[0][1]*c[0][1].a*/0, CWA8[0][2]*c[0][2].a, CWA8[0][3]*c[0][3].a, CWA8[0][4]*c[0][4].a, CWA8[0][5]*c[0][5].a,/*CWA8[0][6]*c[0][6].a*/0,/*CWA8[0][7]*c[0][7].a*/0},
  3338. {/*CWA8[1][0]*c[1][0].a*/0, CWA8[1][1]*c[1][1].a , CWA8[1][2]*c[1][2].a, CWA8[1][3]*c[1][3].a, CWA8[1][4]*c[1][4].a, CWA8[1][5]*c[1][5].a, CWA8[1][6]*c[1][6].a ,/*CWA8[1][7]*c[1][7].a*/0},
  3339. { CWA8[2][0]*c[2][0].a , CWA8[2][1]*c[2][1].a , CWA8[2][2]*c[2][2].a, CWA8[2][3]*c[2][3].a, CWA8[2][4]*c[2][4].a, CWA8[2][5]*c[2][5].a, CWA8[2][6]*c[2][6].a , CWA8[2][7]*c[2][7].a },
  3340. { CWA8[3][0]*c[3][0].a , CWA8[3][1]*c[3][1].a , CWA8[3][2]*c[3][2].a, CWA8[3][3]*c[3][3].a, CWA8[3][4]*c[3][4].a, CWA8[3][5]*c[3][5].a, CWA8[3][6]*c[3][6].a , CWA8[3][7]*c[3][7].a },
  3341. { CWA8[4][0]*c[4][0].a , CWA8[4][1]*c[4][1].a , CWA8[4][2]*c[4][2].a, CWA8[4][3]*c[4][3].a, CWA8[4][4]*c[4][4].a, CWA8[4][5]*c[4][5].a, CWA8[4][6]*c[4][6].a , CWA8[4][7]*c[4][7].a },
  3342. { CWA8[5][0]*c[5][0].a , CWA8[5][1]*c[5][1].a , CWA8[5][2]*c[5][2].a, CWA8[5][3]*c[5][3].a, CWA8[5][4]*c[5][4].a, CWA8[5][5]*c[5][5].a, CWA8[5][6]*c[5][6].a , CWA8[5][7]*c[5][7].a },
  3343. {/*CWA8[6][0]*c[6][0].a*/0, CWA8[6][1]*c[6][1].a , CWA8[6][2]*c[6][2].a, CWA8[6][3]*c[6][3].a, CWA8[6][4]*c[6][4].a, CWA8[6][5]*c[6][5].a, CWA8[6][6]*c[6][6].a ,/*CWA8[6][7]*c[6][7].a*/0},
  3344. {/*CWA8[7][0]*c[7][0].a*/0,/*CWA8[7][1]*c[7][1].a*/0, CWA8[7][2]*c[7][2].a, CWA8[7][3]*c[7][3].a, CWA8[7][4]*c[7][4].a, CWA8[7][5]*c[7][5].a,/*CWA8[7][6]*c[7][6].a*/0,/*CWA8[7][7]*c[7][7].a*/0}};
  3345. Int div=/*w[0][0] + w[0][1]*/+ w[0][2] + w[0][3] + w[0][4] + w[0][5]/*+ w[0][6] + w[0][7]*/
  3346. /*+ w[1][0]*/+ w[1][1] + w[1][2] + w[1][3] + w[1][4] + w[1][5] + w[1][6]/*+ w[1][7]*/
  3347. + w[2][0] + w[2][1] + w[2][2] + w[2][3] + w[2][4] + w[2][5] + w[2][6] + w[2][7]
  3348. + w[3][0] + w[3][1] + w[3][2] + w[3][3] + w[3][4] + w[3][5] + w[3][6] + w[3][7]
  3349. + w[4][0] + w[4][1] + w[4][2] + w[4][3] + w[4][4] + w[4][5] + w[4][6] + w[4][7]
  3350. + w[5][0] + w[5][1] + w[5][2] + w[5][3] + w[5][4] + w[5][5] + w[5][6] + w[5][7]
  3351. /*+ w[6][0]*/+ w[6][1] + w[6][2] + w[6][3] + w[6][4] + w[6][5] + w[6][6]/*+ w[6][7]*/
  3352. /*+ w[7][0] + w[7][1]*/+ w[7][2] + w[7][3] + w[7][4] + w[7][5]/*+ w[7][6] + w[7][7]*/;
  3353. if(div<=0){col.a=0; goto cubic_sharp_rgb;}
  3354. col.a=Min(DivRound(div, CWA8Sum), 255); // here "div>0" so no need to do "Max(0, "
  3355. if(div<CWA8AlphaLimit) // below this limit, lerp to RGB
  3356. {
  3357. // instead of lerping actual colors, we lerp just the weights, it is an approximation and does not provide the same results as float version, however it is faster
  3358. // weights are lerped between "CWA8[y][x]" (alpha_weight=false) and "CWA8[y][x]*c[y][x].a" (alpha_weight=true)
  3359. // since the right side has a scale of "c[y][x].a", we multiply the left side by "Max(col.a, 1)" (average alpha value, and max 1 to avoid having zero weights and division by zero later)
  3360. #if 0 // float version
  3361. C Flt blend=Flt(div)/CWA8AlphaLimit;
  3362. REPD(y, 8)
  3363. REPD(x, 8)w[y][x]=Lerp(CWA8[y][x]*Max(col.a, 1), w[y][x], blend);
  3364. #else // integer version
  3365. C Int d=256, blend=div/d, blend1=(CWA8AlphaLimit/d-blend)*Max(col.a, 1);
  3366. REPD(y, 8)
  3367. REPD(x, 8)w[y][x]=(CWA8[y][x]*blend1 + w[y][x]*blend)>>10;
  3368. #endif
  3369. // recalculate 'div'
  3370. div=/*w[0][0] + w[0][1]*/+ w[0][2] + w[0][3] + w[0][4] + w[0][5]/*+ w[0][6] + w[0][7]*/
  3371. /*+ w[1][0]*/+ w[1][1] + w[1][2] + w[1][3] + w[1][4] + w[1][5] + w[1][6]/*+ w[1][7]*/
  3372. + w[2][0] + w[2][1] + w[2][2] + w[2][3] + w[2][4] + w[2][5] + w[2][6] + w[2][7]
  3373. + w[3][0] + w[3][1] + w[3][2] + w[3][3] + w[3][4] + w[3][5] + w[3][6] + w[3][7]
  3374. + w[4][0] + w[4][1] + w[4][2] + w[4][3] + w[4][4] + w[4][5] + w[4][6] + w[4][7]
  3375. + w[5][0] + w[5][1] + w[5][2] + w[5][3] + w[5][4] + w[5][5] + w[5][6] + w[5][7]
  3376. /*+ w[6][0]*/+ w[6][1] + w[6][2] + w[6][3] + w[6][4] + w[6][5] + w[6][6]/*+ w[6][7]*/
  3377. /*+ w[7][0] + w[7][1]*/+ w[7][2] + w[7][3] + w[7][4] + w[7][5]/*+ w[7][6] + w[7][7]*/;
  3378. }
  3379. Int div_2=div>>1;
  3380. col.r=Mid((/*c[0][0].r*w[0][0] + c[0][1].r*w[0][1]*/+ c[0][2].r*w[0][2] + c[0][3].r*w[0][3] + c[0][4].r*w[0][4] + c[0][5].r*w[0][5] +/*c[0][6].r*w[0][6] + c[0][7].r*w[0][7]*/
  3381. /*+ c[1][0].r*w[1][0]*/+ c[1][1].r*w[1][1] + c[1][2].r*w[1][2] + c[1][3].r*w[1][3] + c[1][4].r*w[1][4] + c[1][5].r*w[1][5] + c[1][6].r*w[1][6] +/*c[1][7].r*w[1][7]*/
  3382. + c[2][0].r*w[2][0] + c[2][1].r*w[2][1] + c[2][2].r*w[2][2] + c[2][3].r*w[2][3] + c[2][4].r*w[2][4] + c[2][5].r*w[2][5] + c[2][6].r*w[2][6] + c[2][7].r*w[2][7]
  3383. + c[3][0].r*w[3][0] + c[3][1].r*w[3][1] + c[3][2].r*w[3][2] + c[3][3].r*w[3][3] + c[3][4].r*w[3][4] + c[3][5].r*w[3][5] + c[3][6].r*w[3][6] + c[3][7].r*w[3][7]
  3384. + c[4][0].r*w[4][0] + c[4][1].r*w[4][1] + c[4][2].r*w[4][2] + c[4][3].r*w[4][3] + c[4][4].r*w[4][4] + c[4][5].r*w[4][5] + c[4][6].r*w[4][6] + c[4][7].r*w[4][7]
  3385. + c[5][0].r*w[5][0] + c[5][1].r*w[5][1] + c[5][2].r*w[5][2] + c[5][3].r*w[5][3] + c[5][4].r*w[5][4] + c[5][5].r*w[5][5] + c[5][6].r*w[5][6] + c[5][7].r*w[5][7]
  3386. /*+ c[6][0].r*w[6][0]*/+ c[6][1].r*w[6][1] + c[6][2].r*w[6][2] + c[6][3].r*w[6][3] + c[6][4].r*w[6][4] + c[6][5].r*w[6][5] + c[6][6].r*w[6][6] +/*c[6][7].r*w[6][7]*/
  3387. /*+ c[7][0].r*w[7][0] + c[7][1].r*w[7][1]*/+ c[7][2].r*w[7][2] + c[7][3].r*w[7][3] + c[7][4].r*w[7][4] + c[7][5].r*w[7][5] +/*c[7][6].r*w[7][6] + c[7][7].r*w[7][7]*/ + div_2)/div, 0, 255);
  3388. col.g=Mid((/*c[0][0].g*w[0][0] + c[0][1].g*w[0][1]*/+ c[0][2].g*w[0][2] + c[0][3].g*w[0][3] + c[0][4].g*w[0][4] + c[0][5].g*w[0][5] +/*c[0][6].g*w[0][6] + c[0][7].g*w[0][7]*/
  3389. /*+ c[1][0].g*w[1][0]*/+ c[1][1].g*w[1][1] + c[1][2].g*w[1][2] + c[1][3].g*w[1][3] + c[1][4].g*w[1][4] + c[1][5].g*w[1][5] + c[1][6].g*w[1][6] +/*c[1][7].g*w[1][7]*/
  3390. + c[2][0].g*w[2][0] + c[2][1].g*w[2][1] + c[2][2].g*w[2][2] + c[2][3].g*w[2][3] + c[2][4].g*w[2][4] + c[2][5].g*w[2][5] + c[2][6].g*w[2][6] + c[2][7].g*w[2][7]
  3391. + c[3][0].g*w[3][0] + c[3][1].g*w[3][1] + c[3][2].g*w[3][2] + c[3][3].g*w[3][3] + c[3][4].g*w[3][4] + c[3][5].g*w[3][5] + c[3][6].g*w[3][6] + c[3][7].g*w[3][7]
  3392. + c[4][0].g*w[4][0] + c[4][1].g*w[4][1] + c[4][2].g*w[4][2] + c[4][3].g*w[4][3] + c[4][4].g*w[4][4] + c[4][5].g*w[4][5] + c[4][6].g*w[4][6] + c[4][7].g*w[4][7]
  3393. + c[5][0].g*w[5][0] + c[5][1].g*w[5][1] + c[5][2].g*w[5][2] + c[5][3].g*w[5][3] + c[5][4].g*w[5][4] + c[5][5].g*w[5][5] + c[5][6].g*w[5][6] + c[5][7].g*w[5][7]
  3394. /*+ c[6][0].g*w[6][0]*/+ c[6][1].g*w[6][1] + c[6][2].g*w[6][2] + c[6][3].g*w[6][3] + c[6][4].g*w[6][4] + c[6][5].g*w[6][5] + c[6][6].g*w[6][6] +/*c[6][7].g*w[6][7]*/
  3395. /*+ c[7][0].g*w[7][0] + c[7][1].g*w[7][1]*/+ c[7][2].g*w[7][2] + c[7][3].g*w[7][3] + c[7][4].g*w[7][4] + c[7][5].g*w[7][5] +/*c[7][6].g*w[7][6] + c[7][7].g*w[7][7]*/ + div_2)/div, 0, 255);
  3396. col.b=Mid((/*c[0][0].b*w[0][0] + c[0][1].b*w[0][1]*/+ c[0][2].b*w[0][2] + c[0][3].b*w[0][3] + c[0][4].b*w[0][4] + c[0][5].b*w[0][5] +/*c[0][6].b*w[0][6] + c[0][7].b*w[0][7]*/
  3397. /*+ c[1][0].b*w[1][0]*/+ c[1][1].b*w[1][1] + c[1][2].b*w[1][2] + c[1][3].b*w[1][3] + c[1][4].b*w[1][4] + c[1][5].b*w[1][5] + c[1][6].b*w[1][6] +/*c[1][7].b*w[1][7]*/
  3398. + c[2][0].b*w[2][0] + c[2][1].b*w[2][1] + c[2][2].b*w[2][2] + c[2][3].b*w[2][3] + c[2][4].b*w[2][4] + c[2][5].b*w[2][5] + c[2][6].b*w[2][6] + c[2][7].b*w[2][7]
  3399. + c[3][0].b*w[3][0] + c[3][1].b*w[3][1] + c[3][2].b*w[3][2] + c[3][3].b*w[3][3] + c[3][4].b*w[3][4] + c[3][5].b*w[3][5] + c[3][6].b*w[3][6] + c[3][7].b*w[3][7]
  3400. + c[4][0].b*w[4][0] + c[4][1].b*w[4][1] + c[4][2].b*w[4][2] + c[4][3].b*w[4][3] + c[4][4].b*w[4][4] + c[4][5].b*w[4][5] + c[4][6].b*w[4][6] + c[4][7].b*w[4][7]
  3401. + c[5][0].b*w[5][0] + c[5][1].b*w[5][1] + c[5][2].b*w[5][2] + c[5][3].b*w[5][3] + c[5][4].b*w[5][4] + c[5][5].b*w[5][5] + c[5][6].b*w[5][6] + c[5][7].b*w[5][7]
  3402. /*+ c[6][0].b*w[6][0]*/+ c[6][1].b*w[6][1] + c[6][2].b*w[6][2] + c[6][3].b*w[6][3] + c[6][4].b*w[6][4] + c[6][5].b*w[6][5] + c[6][6].b*w[6][6] +/*c[6][7].b*w[6][7]*/
  3403. /*+ c[7][0].b*w[7][0] + c[7][1].b*w[7][1]*/+ c[7][2].b*w[7][2] + c[7][3].b*w[7][3] + c[7][4].b*w[7][4] + c[7][5].b*w[7][5] +/*c[7][6].b*w[7][6] + c[7][7].b*w[7][7]*/ + div_2)/div, 0, 255);
  3404. }
  3405. dest.color(x, y, col);
  3406. }
  3407. }
  3408. goto finish;
  3409. } // if(!high_prec)
  3410. }break;
  3411. case FILTER_CUBIC_FAST_SMOOTH: // used by 'transparentToNeighbor'
  3412. {
  3413. REPD(y, dest.h())
  3414. {
  3415. Int yc[8]; yc[3]=y*2; // 'y[3]' is always OK
  3416. if(clamp){yc[0]=Max(yc[3]-3, 0 ); yc[1]=Max(yc[3]-2, 0 ); yc[2]=Max(yc[3]-1, 0 ); yc[4]=Min(yc[3]+1, h()-1); yc[5]=Min(yc[3]+2, h()-1); yc[6]=Min(yc[3]+3, h()-1); yc[7]=Min(yc[3]+4, h()-1);}
  3417. else {yc[0]=Mod(yc[3]-3, h()); yc[1]=Mod(yc[3]-2, h()); yc[2]=Mod(yc[3]-1, h()); yc[4]= (yc[3]+1)%h() ; yc[5]= (yc[3]+2)%h() ; yc[6]= (yc[3]+3)%h() ; yc[7]= (yc[3]+4)%h() ;}
  3418. REPD(x, dest.w())
  3419. {
  3420. Int xc[8]; xc[3]=x*2; // 'x[3]' is always OK
  3421. if(clamp){xc[0]=Max(xc[3]-3, 0 ); xc[1]=Max(xc[3]-2, 0 ); xc[2]=Max(xc[3]-1, 0 ); xc[4]=Min(xc[3]+1, w()-1); xc[5]=Min(xc[3]+2, w()-1); xc[6]=Min(xc[3]+3, w()-1); xc[7]=Min(xc[3]+4, w()-1);}
  3422. else {xc[0]=Mod(xc[3]-3, w()); xc[1]=Mod(xc[3]-2, w()); xc[2]=Mod(xc[3]-1, w()); xc[4]= (xc[3]+1)%w() ; xc[5]= (xc[3]+2)%w() ; xc[6]= (xc[3]+3)%w() ; xc[7]= (xc[3]+4)%w() ;}
  3423. Vec rgb=0; Vec4 color=0, c[8][8]; // [y][x]
  3424. gather(&c[0][0], xc, Elms(xc), yc, Elms(yc));
  3425. REPD(x, 8)
  3426. REPD(y, 8)if(Flt w=CFSMW8[y][x])Add(color, rgb, c[y][x], w, alpha_weight);
  3427. Normalize(color, rgb, alpha_weight, t_high_prec);
  3428. dest.colorF(x, y, color);
  3429. }
  3430. }
  3431. }goto finish;
  3432. } // switch(filter)
  3433. }else // 3D
  3434. {
  3435. switch(filter)
  3436. {
  3437. case FILTER_NONE: REPD(z, dest.d())
  3438. {
  3439. Int zc=z*2; REPD(y, dest.h())
  3440. {
  3441. Int yc=y*2;
  3442. if(high_prec)REPD(x, dest.w())dest.color3DF(x, y, z, color3DF(x*2, yc, zc));
  3443. else REPD(x, dest.w())dest.color3D (x, y, z, color3D (x*2, yc, zc));
  3444. }
  3445. }goto finish;
  3446. case FILTER_LINEAR:
  3447. {
  3448. if(!high_prec)
  3449. {
  3450. REPD(z, dest.d())
  3451. {
  3452. Int zc[2]; zc[0]=z*2; zc[1]=(clamp ? Min(zc[0]+1, d()-1) : (zc[0]+1)%d()); // zc[0] is always OK
  3453. REPD(y, dest.h())
  3454. {
  3455. Int yc[2]; yc[0]=y*2; yc[1]=(clamp ? Min(yc[0]+1, h()-1) : (yc[0]+1)%h()); // yc[0] is always OK
  3456. REPD(x, dest.w())
  3457. {
  3458. Int xc[2]; xc[0]=x*2; xc[1]=(clamp ? Min(xc[0]+1, w()-1) : (xc[0]+1)%w()); // xc[0] is always OK
  3459. Color col, c[2][2][2]; gather(&c[0][0][0], xc, Elms(xc), yc, Elms(yc), zc, Elms(zc)); // [z][y][x]
  3460. if(!alpha_weight)
  3461. {
  3462. col.a=((c[0][0][0].a+c[0][0][1].a+c[0][1][0].a+c[0][1][1].a+c[1][0][0].a+c[1][0][1].a+c[1][1][0].a+c[1][1][1].a+4)>>3);
  3463. linear_rgb_3D:
  3464. col.r=((c[0][0][0].r+c[0][0][1].r+c[0][1][0].r+c[0][1][1].r+c[1][0][0].r+c[1][0][1].r+c[1][1][0].r+c[1][1][1].r+4)>>3);
  3465. col.g=((c[0][0][0].g+c[0][0][1].g+c[0][1][0].g+c[0][1][1].g+c[1][0][0].g+c[1][0][1].g+c[1][1][0].g+c[1][1][1].g+4)>>3);
  3466. col.b=((c[0][0][0].b+c[0][0][1].b+c[0][1][0].b+c[0][1][1].b+c[1][0][0].b+c[1][0][1].b+c[1][1][0].b+c[1][1][1].b+4)>>3);
  3467. }else
  3468. {
  3469. UInt a=c[0][0][0].a+c[0][0][1].a+c[0][1][0].a+c[0][1][1].a+c[1][0][0].a+c[1][0][1].a+c[1][1][0].a+c[1][1][1].a;
  3470. if( !a){col.a=0; goto linear_rgb_3D;}
  3471. col.a=((a+4)>>3); UInt a_2=a>>1;
  3472. col.r=(c[0][0][0].r*c[0][0][0].a + c[0][0][1].r*c[0][0][1].a + c[0][1][0].r*c[0][1][0].a + c[0][1][1].r*c[0][1][1].a + c[1][0][0].r*c[1][0][0].a + c[1][0][1].r*c[1][0][1].a + c[1][1][0].r*c[1][1][0].a + c[1][1][1].r*c[1][1][1].a + a_2)/a;
  3473. col.g=(c[0][0][0].g*c[0][0][0].a + c[0][0][1].g*c[0][0][1].a + c[0][1][0].g*c[0][1][0].a + c[0][1][1].g*c[0][1][1].a + c[1][0][0].g*c[1][0][0].a + c[1][0][1].g*c[1][0][1].a + c[1][1][0].g*c[1][1][0].a + c[1][1][1].g*c[1][1][1].a + a_2)/a;
  3474. col.b=(c[0][0][0].b*c[0][0][0].a + c[0][0][1].b*c[0][0][1].a + c[0][1][0].b*c[0][1][0].a + c[0][1][1].b*c[0][1][1].a + c[1][0][0].b*c[1][0][0].a + c[1][0][1].b*c[1][0][1].a + c[1][1][0].b*c[1][1][0].a + c[1][1][1].b*c[1][1][1].a + a_2)/a;
  3475. }
  3476. dest.color3D(x, y, z, col);
  3477. }
  3478. }
  3479. }
  3480. goto finish;
  3481. }
  3482. }break;
  3483. }
  3484. }
  3485. }
  3486. // any scale
  3487. {
  3488. // for scale 1->1 offset=0.0
  3489. // 2->1 offset=0.5
  3490. // 3->1 offset=1.0
  3491. // 4->1 offset=1.5
  3492. Vec2 x_mul_add, y_mul_add, z_mul_add;
  3493. if(keep_edges)
  3494. {
  3495. x_mul_add.set(Flt(T.w()-1)/(dest.w()-1), 0);
  3496. y_mul_add.set(Flt(T.h()-1)/(dest.h()-1), 0);
  3497. z_mul_add.set(Flt(T.d()-1)/(dest.d()-1), 0);
  3498. }else
  3499. {
  3500. x_mul_add.x=Flt(T.w())/dest.w(); x_mul_add.y=x_mul_add.x*0.5f-0.5f;
  3501. y_mul_add.x=Flt(T.h())/dest.h(); y_mul_add.y=y_mul_add.x*0.5f-0.5f;
  3502. z_mul_add.x=Flt(T.d())/dest.d(); z_mul_add.y=z_mul_add.x*0.5f-0.5f;
  3503. }
  3504. Vec size(x_mul_add.x, y_mul_add.x, z_mul_add.x); size*=sharp_smooth;
  3505. if(filter!=FILTER_NONE && (size.x>1 || size.y>1) && T.d()==1 && dest.d()==1) // if we're downsampling (any scale is higher than 1) then we must use more complex 'areaColor*' methods
  3506. {
  3507. Vec4 (Image::*area_color)(C Vec2 &pos, C Vec2 &size, Bool clamp, Bool alpha_weight)C; // pointer to class method
  3508. switch(filter)
  3509. {
  3510. //case FILTER_AVERAGE : area_color=&Image::areaColorAverage ; break;
  3511. case FILTER_LINEAR : area_color=&Image::areaColorLinear ; break;
  3512. case FILTER_CUBIC_FAST : area_color=&Image::areaColorCubicFast ; break;
  3513. case FILTER_CUBIC_FAST_SMOOTH: area_color=&Image::areaColorCubicFastSmooth; break;
  3514. default : // FILTER_BEST
  3515. case FILTER_CUBIC_FAST_SHARP : area_color=&Image::areaColorCubicFastSharp ; break; ASSERT(FILTER_DOWN==FILTER_CUBIC_FAST_SHARP);
  3516. case FILTER_CUBIC : area_color=&Image::areaColorCubic ; break;
  3517. case FILTER_CUBIC_SHARP : area_color=&Image::areaColorCubicSharp ; break;
  3518. }
  3519. Vec2 pos;
  3520. REPD(y, dest.h())
  3521. {
  3522. pos.y=y*y_mul_add.x+y_mul_add.y;
  3523. REPD(x, dest.w())
  3524. {
  3525. pos.x=x*x_mul_add.x+x_mul_add.y;
  3526. dest.colorF(x, y, (T.*area_color)(pos, size.xy, clamp, alpha_weight));
  3527. }
  3528. }
  3529. }else
  3530. if((filter==FILTER_CUBIC || filter==FILTER_CUBIC_SHARP || filter==FILTER_BEST) // optimized Cubic/Best upscale
  3531. && T.d()==1)
  3532. {
  3533. Flt (*Func)(Flt x)=((filter==FILTER_CUBIC_SHARP) ? CubicSharp2 : CubicMed2); ASSERT(CUBIC_MED_SAMPLES==CUBIC_SHARP_SAMPLES && CUBIC_MED_RANGE==CUBIC_SHARP_RANGE && CUBIC_MED_SHARPNESS==CUBIC_SHARP_SHARPNESS);
  3534. REPD(z, dest.d())
  3535. {
  3536. Byte *dest_data_z=dest.data() + z*dest.pitch2();
  3537. FREPD(y, dest.h())
  3538. {
  3539. Byte *dest_data_y=dest_data_z + y*dest.pitch();
  3540. Flt sy=y*y_mul_add.x+y_mul_add.y,
  3541. sx=/*x*x_mul_add.x+*/x_mul_add.y; // 'x' is zero at this step so ignore it
  3542. Int xo[CUBIC_MED_SAMPLES*2], yo[CUBIC_MED_SAMPLES*2], xi=Floor(sx), yi=Floor(sy);
  3543. Flt yw[CUBIC_MED_SAMPLES*2];
  3544. REPA( xo)
  3545. {
  3546. xo[i]=xi-CUBIC_MED_SAMPLES+1+i;
  3547. yo[i]=yi-CUBIC_MED_SAMPLES+1+i; yw[i]=Sqr(sy-yo[i]);
  3548. if(clamp)
  3549. {
  3550. Clamp(xo[i], 0, lw()-1);
  3551. Clamp(yo[i], 0, lh()-1);
  3552. }else
  3553. {
  3554. xo[i]=Mod(xo[i], lw());
  3555. yo[i]=Mod(yo[i], lh());
  3556. }
  3557. }
  3558. if(NeedMultiChannel(T.type(), dest.type()))
  3559. {
  3560. Vec4 c[CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2];
  3561. gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  3562. REPD(x, CUBIC_MED_SAMPLES*2)REPD(y, x)Swap(c[y][x], c[x][y]); // convert [y][x] -> [x][y] so we can use later 'gather' to read a single column with new x
  3563. Int x_offset=0;
  3564. FREPD(x, dest.w())
  3565. {
  3566. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3567. Int xi2=Floor(sx); if(xi!=xi2)
  3568. {
  3569. xi=xi2;
  3570. Int xo_last=xi+CUBIC_MED_SAMPLES; if(clamp)Clamp(xo_last, 0, lw()-1);else xo_last=Mod(xo_last, lw());
  3571. gather(&c[x_offset][0], &xo_last, 1, yo, Elms(yo)); // read new column
  3572. x_offset=(x_offset+1)%(CUBIC_MED_SAMPLES*2);
  3573. }
  3574. Flt weight=0;
  3575. Vec rgb =0;
  3576. Vec4 color =0;
  3577. REPAD(x, xo)
  3578. {
  3579. Int xc=(x+x_offset)%(CUBIC_MED_SAMPLES*2);
  3580. Flt xw=Sqr(sx-(xi-CUBIC_MED_SAMPLES+1+x));
  3581. REPAD(y, yo)
  3582. {
  3583. Flt w=xw+yw[y]; if(w<Sqr(CUBIC_MED_RANGE))
  3584. {
  3585. w=Func(w*Sqr(CUBIC_MED_SHARPNESS)); Add(color, rgb, c[xc][y], w, alpha_weight); weight+=w;
  3586. }
  3587. }
  3588. }
  3589. Normalize(color, rgb, weight, alpha_weight, t_high_prec);
  3590. StoreColor(dest, dest_data_y, x, y, z, color);
  3591. }
  3592. }else
  3593. {
  3594. Flt v[CUBIC_MED_SAMPLES*2][CUBIC_MED_SAMPLES*2];
  3595. gather(&v[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  3596. REPD(x, CUBIC_MED_SAMPLES*2)REPD(y, x)Swap(v[y][x], v[x][y]); // convert [y][x] -> [x][y] so we can use later 'gather' to read a single column with new x
  3597. Int x_offset=0;
  3598. FREPD(x, dest.w())
  3599. {
  3600. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3601. Int xi2=Floor(sx); if(xi!=xi2)
  3602. {
  3603. xi=xi2;
  3604. Int xo_last=xi+CUBIC_MED_SAMPLES; if(clamp)Clamp(xo_last, 0, lw()-1);else xo_last=Mod(xo_last, lw());
  3605. gather(&v[x_offset][0], &xo_last, 1, yo, Elms(yo)); // read new column
  3606. x_offset=(x_offset+1)%(CUBIC_MED_SAMPLES*2);
  3607. }
  3608. Flt weight=0, value=0;
  3609. REPAD(x, xo)
  3610. {
  3611. Int xc=(x+x_offset)%(CUBIC_MED_SAMPLES*2);
  3612. Flt xw=Sqr(sx-(xi-CUBIC_MED_SAMPLES+1+x));
  3613. REPAD(y, yo)
  3614. {
  3615. Flt w=xw+yw[y]; if(w<Sqr(CUBIC_MED_RANGE))
  3616. {
  3617. w=Func(w*Sqr(CUBIC_MED_SHARPNESS)); value+=v[xc][y]*w; weight+=w;
  3618. }
  3619. }
  3620. }
  3621. StorePixel(dest, dest_data_y, x, y, z, value/weight);
  3622. }
  3623. }
  3624. }
  3625. }
  3626. }else
  3627. if((filter==FILTER_CUBIC_FAST || filter==FILTER_CUBIC_FAST_SMOOTH || filter==FILTER_CUBIC_FAST_SHARP) // optimized CubicFast upscale
  3628. && T.d()==1)
  3629. {
  3630. Flt (*Func)(Flt x)=((filter==FILTER_CUBIC_FAST) ? CubicFast2 : (filter==FILTER_CUBIC_FAST_SMOOTH) ? CubicFastSmooth2 : CubicFastSharp2);
  3631. REPD(z, dest.d())
  3632. {
  3633. Byte *dest_data_z=dest.data() + z*dest.pitch2();
  3634. FREPD(y, dest.h())
  3635. {
  3636. Byte *dest_data_y=dest_data_z + y*dest.pitch();
  3637. Flt sy=y*y_mul_add.x+y_mul_add.y,
  3638. sx=/*x*x_mul_add.x+*/x_mul_add.y; // 'x' is zero at this step so ignore it
  3639. Int xo[CUBIC_FAST_SAMPLES*2], yo[CUBIC_FAST_SAMPLES*2], xi=Floor(sx), yi=Floor(sy);
  3640. Flt yw[CUBIC_FAST_SAMPLES*2];
  3641. REPA( xo)
  3642. {
  3643. xo[i]=xi-CUBIC_FAST_SAMPLES+1+i;
  3644. yo[i]=yi-CUBIC_FAST_SAMPLES+1+i; yw[i]=Sqr(sy-yo[i]);
  3645. if(clamp)
  3646. {
  3647. Clamp(xo[i], 0, lw()-1);
  3648. Clamp(yo[i], 0, lh()-1);
  3649. }else
  3650. {
  3651. xo[i]=Mod(xo[i], lw());
  3652. yo[i]=Mod(yo[i], lh());
  3653. }
  3654. }
  3655. if(NeedMultiChannel(T.type(), dest.type()))
  3656. {
  3657. Vec4 c[CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  3658. gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  3659. REPD(x, CUBIC_FAST_SAMPLES*2)REPD(y, x)Swap(c[y][x], c[x][y]); // convert [y][x] -> [x][y] so we can use later 'gather' to read a single column with new x
  3660. Int x_offset=0;
  3661. FREPD(x, dest.w())
  3662. {
  3663. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3664. Int xi2=Floor(sx); if(xi!=xi2)
  3665. {
  3666. xi=xi2;
  3667. Int xo_last=xi+CUBIC_FAST_SAMPLES; if(clamp)Clamp(xo_last, 0, lw()-1);else xo_last=Mod(xo_last, lw());
  3668. gather(&c[x_offset][0], &xo_last, 1, yo, Elms(yo)); // read new column
  3669. x_offset=(x_offset+1)%(CUBIC_FAST_SAMPLES*2);
  3670. }
  3671. Flt weight=0;
  3672. Vec rgb =0;
  3673. Vec4 color =0;
  3674. REPAD(x, xo)
  3675. {
  3676. Int xc=(x+x_offset)%(CUBIC_FAST_SAMPLES*2);
  3677. Flt xw=Sqr(sx-(xi-CUBIC_FAST_SAMPLES+1+x));
  3678. REPAD(y, yo)
  3679. {
  3680. Flt w=xw+yw[y]; if(w<Sqr(CUBIC_FAST_RANGE))
  3681. {
  3682. w=Func(w); Add(color, rgb, c[xc][y], w, alpha_weight); weight+=w;
  3683. }
  3684. }
  3685. }
  3686. Normalize(color, rgb, weight, alpha_weight, t_high_prec);
  3687. StoreColor(dest, dest_data_y, x, y, z, color);
  3688. }
  3689. }else
  3690. {
  3691. Flt v[CUBIC_FAST_SAMPLES*2][CUBIC_FAST_SAMPLES*2];
  3692. gather(&v[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  3693. REPD(x, CUBIC_FAST_SAMPLES*2)REPD(y, x)Swap(v[y][x], v[x][y]); // convert [y][x] -> [x][y] so we can use later 'gather' to read a single column with new x
  3694. Int x_offset=0;
  3695. FREPD(x, dest.w())
  3696. {
  3697. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3698. Int xi2=Floor(sx); if(xi!=xi2)
  3699. {
  3700. xi=xi2;
  3701. Int xo_last=xi+CUBIC_FAST_SAMPLES; if(clamp)Clamp(xo_last, 0, lw()-1);else xo_last=Mod(xo_last, lw());
  3702. gather(&v[x_offset][0], &xo_last, 1, yo, Elms(yo)); // read new column
  3703. x_offset=(x_offset+1)%(CUBIC_FAST_SAMPLES*2);
  3704. }
  3705. Flt weight=0, value=0;
  3706. REPAD(x, xo)
  3707. {
  3708. Int xc=(x+x_offset)%(CUBIC_FAST_SAMPLES*2);
  3709. Flt xw=Sqr(sx-(xi-CUBIC_FAST_SAMPLES+1+x));
  3710. REPAD(y, yo)
  3711. {
  3712. Flt w=xw+yw[y]; if(w<Sqr(CUBIC_FAST_RANGE))
  3713. {
  3714. w=Func(w); value+=v[xc][y]*w; weight+=w;
  3715. }
  3716. }
  3717. }
  3718. StorePixel(dest, dest_data_y, x, y, z, value/weight);
  3719. }
  3720. }
  3721. }
  3722. }
  3723. }else
  3724. if(filter==FILTER_LINEAR // optimized Linear upscale, this is used for Texture Sharpness calculation
  3725. && T.d()==1)
  3726. {
  3727. REPD(z, dest.d())
  3728. {
  3729. Byte *dest_data_z=dest.data() + z*dest.pitch2();
  3730. FREPD(y, dest.h())
  3731. {
  3732. Byte *dest_data_y=dest_data_z + y*dest.pitch();
  3733. Flt sy=y*y_mul_add.x+y_mul_add.y,
  3734. sx=/*x*x_mul_add.x+*/x_mul_add.y; // 'x' is zero at this step so ignore it
  3735. Int xo[2], yo[2], xi=Floor(sx), yi=Floor(sy);
  3736. Flt yw[2]; yw[1]=sy-yi; yw[0]=1-yw[1];
  3737. REPA( xo)
  3738. {
  3739. xo[i]=xi+i;
  3740. yo[i]=yi+i;
  3741. if(clamp)
  3742. {
  3743. Clamp(xo[i], 0, lw()-1);
  3744. Clamp(yo[i], 0, lh()-1);
  3745. }else
  3746. {
  3747. xo[i]=Mod(xo[i], lw());
  3748. yo[i]=Mod(yo[i], lh());
  3749. }
  3750. }
  3751. if(NeedMultiChannel(T.type(), dest.type()))
  3752. {
  3753. Vec4 c[2][2];
  3754. gather(&c[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  3755. REPD(x, 2)REPD(y, x)Swap(c[y][x], c[x][y]); // convert [y][x] -> [x][y] so we can use later 'gather' to read a single column with new x
  3756. Int x_offset=0;
  3757. FREPD(x, dest.w())
  3758. {
  3759. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3760. Int xi2=Floor(sx); if(xi!=xi2)
  3761. {
  3762. xi=xi2;
  3763. Int xo_last=xi+1; if(clamp)Clamp(xo_last, 0, lw()-1);else xo_last=Mod(xo_last, lw());
  3764. gather(&c[x_offset][0], &xo_last, 1, yo, Elms(yo)); // read new column
  3765. x_offset^=1;
  3766. }
  3767. Vec rgb =0;
  3768. Vec4 color=0;
  3769. Flt xw[2]; xw[1]=sx-xi; xw[0]=1-xw[1];
  3770. REPAD(x, xo)
  3771. {
  3772. Int xc=(x+x_offset)&1;
  3773. REPAD(y, yo)Add(color, rgb, c[xc][y], xw[x]*yw[y], alpha_weight);
  3774. }
  3775. Normalize(color, rgb, alpha_weight, t_high_prec);
  3776. StoreColor(dest, dest_data_y, x, y, z, color);
  3777. }
  3778. }else
  3779. {
  3780. Flt v[2][2];
  3781. gather(&v[0][0], xo, Elms(xo), yo, Elms(yo)); // [y][x]
  3782. REPD(x, 2)REPD(y, x)Swap(v[y][x], v[x][y]); // convert [y][x] -> [x][y] so we can use later 'gather' to read a single column with new x
  3783. Int x_offset=0;
  3784. FREPD(x, dest.w())
  3785. {
  3786. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3787. Int xi2=Floor(sx); if(xi!=xi2)
  3788. {
  3789. xi=xi2;
  3790. Int xo_last=xi+1; if(clamp)Clamp(xo_last, 0, lw()-1);else xo_last=Mod(xo_last, lw());
  3791. gather(&v[x_offset][0], &xo_last, 1, yo, Elms(yo)); // read new column
  3792. x_offset^=1;
  3793. }
  3794. Flt value=0, xw[2]; xw[1]=sx-xi; xw[0]=1-xw[1];
  3795. REPAD(x, xo)
  3796. {
  3797. Int xc=(x+x_offset)&1;
  3798. REPAD(y, yo)value+=v[xc][y]*xw[x]*yw[y];
  3799. }
  3800. StorePixel(dest, dest_data_y, x, y, z, value);
  3801. }
  3802. }
  3803. }
  3804. }
  3805. }else
  3806. if(NeedMultiChannel(T.type(), dest.type()))
  3807. {
  3808. REPD(z, dest.d())
  3809. {
  3810. Flt sz=z*z_mul_add.x+z_mul_add.y;
  3811. REPD(y, dest.h())
  3812. {
  3813. Flt sy=y*y_mul_add.x+y_mul_add.y;
  3814. REPD(x, dest.w())
  3815. {
  3816. Flt sx=x*x_mul_add.x+x_mul_add.y;
  3817. Vec4 color;
  3818. switch(filter)
  3819. {
  3820. case FILTER_NONE : color=((T.d()<=1) ? T.colorF (RoundPos(sx), RoundPos(sy) ) : T.color3DF (RoundPos(sx), RoundPos(sy), RoundPos(sz) )); break;
  3821. case FILTER_LINEAR : color=((T.d()<=1) ? T.colorFLinear ( sx , sy , clamp, alpha_weight) : T.color3DFLinear ( sx , sy , sz , clamp)); break;
  3822. case FILTER_CUBIC_FAST : color=((T.d()<=1) ? T.colorFCubicFast ( sx , sy , clamp, alpha_weight) : T.color3DFCubicFast ( sx , sy , sz , clamp)); break;
  3823. case FILTER_CUBIC_FAST_SMOOTH: color=((T.d()<=1) ? T.colorFCubicFastSmooth( sx , sy , clamp, alpha_weight) : T.color3DFCubicFastSmooth( sx , sy , sz , clamp)); break;
  3824. case FILTER_CUBIC_FAST_SHARP : color=((T.d()<=1) ? T.colorFCubicFastSharp ( sx , sy , clamp, alpha_weight) : T.color3DFCubicFastSharp ( sx , sy , sz , clamp)); break;
  3825. default : // FILTER_BEST
  3826. case FILTER_CUBIC : color=((T.d()<=1) ? T.colorFCubic ( sx , sy , clamp, alpha_weight) : T.color3DFCubic ( sx , sy , sz , clamp)); break;
  3827. case FILTER_CUBIC_SHARP : color=((T.d()<=1) ? T.colorFCubicSharp ( sx , sy , clamp, alpha_weight) : T.color3DFCubicSharp ( sx , sy , sz , clamp)); break;
  3828. }
  3829. dest.color3DF(x, y, z, color);
  3830. }
  3831. }
  3832. }
  3833. }else
  3834. {
  3835. REPD(z, dest.d())
  3836. {
  3837. Flt sz=z*z_mul_add.x+z_mul_add.y;
  3838. REPD(y, dest.h())
  3839. {
  3840. Flt sy=y*y_mul_add.x+y_mul_add.y;
  3841. REPD(x, dest.w())
  3842. {
  3843. Flt sx=x*x_mul_add.x+x_mul_add.y,
  3844. pix;
  3845. switch(filter)
  3846. {
  3847. case FILTER_NONE : pix=((T.d()<=1) ? T.pixelF (RoundPos(sx), RoundPos(sy) ) : T.pixel3DF (RoundPos(sx), RoundPos(sy), RoundPos(sz) )); break;
  3848. case FILTER_LINEAR : pix=((T.d()<=1) ? T.pixelFLinear ( sx , sy , clamp) : T.pixel3DFLinear ( sx , sy , sz , clamp)); break;
  3849. case FILTER_CUBIC_FAST : pix=((T.d()<=1) ? T.pixelFCubicFast ( sx , sy , clamp) : T.pixel3DFCubicFast ( sx , sy , sz , clamp)); break;
  3850. case FILTER_CUBIC_FAST_SMOOTH: pix=((T.d()<=1) ? T.pixelFCubicFastSmooth( sx , sy , clamp) : T.pixel3DFCubicFastSmooth( sx , sy , sz , clamp)); break;
  3851. case FILTER_CUBIC_FAST_SHARP : pix=((T.d()<=1) ? T.pixelFCubicFastSharp ( sx , sy , clamp) : T.pixel3DFCubicFastSharp ( sx , sy , sz , clamp)); break;
  3852. default : // FILTER_BEST
  3853. case FILTER_CUBIC : pix=((T.d()<=1) ? T.pixelFCubic ( sx , sy , clamp) : T.pixel3DFCubic ( sx , sy , sz , clamp)); break;
  3854. case FILTER_CUBIC_SHARP : pix=((T.d()<=1) ? T.pixelFCubicSharp ( sx , sy , clamp) : T.pixel3DFCubicSharp ( sx , sy , sz , clamp)); break;
  3855. }
  3856. dest.pixel3DF(x, y, z, pix);
  3857. }
  3858. }
  3859. }
  3860. }
  3861. }
  3862. }
  3863. finish:
  3864. dest.unlock();
  3865. T.unlock();
  3866. }
  3867. return true;
  3868. }
  3869. /******************************************************************************/
  3870. }
  3871. /******************************************************************************/