From 0793d31d2b03b82766171241f799ef804f670181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 7 Oct 2018 16:50:59 +0200 Subject: [PATCH] Primitives: new gradient primitive. --- doc/changelog.dox | 4 + doc/generated/primitives.cpp | 87 ++++++++++ doc/primitives-gradient2d.png | Bin 0 -> 24867 bytes doc/primitives-gradient2dhorizontal.png | Bin 0 -> 27596 bytes doc/primitives-gradient2dvertical.png | Bin 0 -> 23932 bytes doc/primitives-gradient3d.png | Bin 0 -> 18495 bytes doc/primitives-gradient3dhorizontal.png | Bin 0 -> 18838 bytes doc/primitives-gradient3dvertical.png | Bin 0 -> 18183 bytes doc/snippets/MagnumPrimitives.cpp | 22 ++- src/Magnum/Primitives/CMakeLists.txt | 2 + src/Magnum/Primitives/Gradient.cpp | 99 ++++++++++++ src/Magnum/Primitives/Gradient.h | 121 ++++++++++++++ src/Magnum/Primitives/Plane.h | 2 +- src/Magnum/Primitives/Square.h | 2 +- src/Magnum/Primitives/Test/CMakeLists.txt | 2 + src/Magnum/Primitives/Test/GradientTest.cpp | 167 ++++++++++++++++++++ 16 files changed, 505 insertions(+), 3 deletions(-) create mode 100644 doc/primitives-gradient2d.png create mode 100644 doc/primitives-gradient2dhorizontal.png create mode 100644 doc/primitives-gradient2dvertical.png create mode 100644 doc/primitives-gradient3d.png create mode 100644 doc/primitives-gradient3dhorizontal.png create mode 100644 doc/primitives-gradient3dvertical.png create mode 100644 src/Magnum/Primitives/Gradient.cpp create mode 100644 src/Magnum/Primitives/Gradient.h create mode 100644 src/Magnum/Primitives/Test/GradientTest.cpp diff --git a/doc/changelog.dox b/doc/changelog.dox index 20dcdaf0e..515adb460 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -160,6 +160,10 @@ See also: @subsubsection changelog-latest-new-primitives Primitives library +- New @ref Primitives::gradient2D(), @ref Primitives::gradient2DHorizontal(), + @ref Primitives::gradient2DVertical(), @ref Primitives::gradient3D(), + @ref Primitives::gradient3DHorizontal() and + @ref Primitives::gradient3DVertical() primitives - New @ref Primitives::line2D(const Vector2&, const Vector2&) and @ref Primitives::line3D(const Vector3&, const Vector3&) overloads for easier creation of arbitrary lines, as transforming the line identities is diff --git a/doc/generated/primitives.cpp b/doc/generated/primitives.cpp index 817ba07a8..ce9600d6e 100644 --- a/doc/generated/primitives.cpp +++ b/doc/generated/primitives.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,14 @@ struct PrimitiveVisualizer: Platform::WindowlessApplication { std::pair icosphereSolid(); std::pair planeSolid(); std::pair uvSphereSolid(); + + std::pair gradient2D(); + std::pair gradient2DHorizontal(); + std::pair gradient2DVertical(); + + std::pair gradient3D(); + std::pair gradient3DHorizontal(); + std::pair gradient3DVertical(); }; namespace { @@ -346,6 +355,52 @@ int PrimitiveVisualizer::exec() { } } + { + Shaders::VertexColor2D shader; + shader.setTransformationProjectionMatrix(Projection2D*Transformation2D); + + for(auto fun: {&PrimitiveVisualizer::gradient2D, + &PrimitiveVisualizer::gradient2DHorizontal, + &PrimitiveVisualizer::gradient2DVertical}) { + multisampleFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth); + + std::string filename; + Containers::Optional data; + std::tie(data, filename) = (this->*fun)(); + + MeshTools::compile(*data) + .draw(shader) + .draw(wireframe2D); + + GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); + Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); + converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); + } + } + + { + Shaders::VertexColor3D shader; + shader.setTransformationProjectionMatrix(Projection3D*Transformation3D); + + for(auto fun: {&PrimitiveVisualizer::gradient3D, + &PrimitiveVisualizer::gradient3DHorizontal, + &PrimitiveVisualizer::gradient3DVertical}) { + multisampleFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth); + + std::string filename; + Containers::Optional data; + std::tie(data, filename) = (this->*fun)(); + + MeshTools::compile(*data) + .draw(shader) + .draw(wireframe3D); + + GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); + Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); + converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); + } + } + return 0; } @@ -353,10 +408,42 @@ std::pair PrimitiveVisualizer::axis2D() { return {Primitives::axis2D(), "axis2d.png"}; } +std::pair PrimitiveVisualizer::gradient2D() { + return {Primitives::gradient2D({1.0f, -2.0f}, 0x2f83cc_srgbf, {-1.0f, 2.0f}, 0x3bd267_srgbf), "gradient2d.png"}; +} + +namespace { + /* End colors for axis-aligned gradients are 20%/80% blends of the above to + match the range */ + const Color3 Gradient20Percent = Math::lerp(0x2f83cc_srgbf, 0x3bd267_srgbf, 0.2f); + const Color3 Gradient80Percent = Math::lerp(0x2f83cc_srgbf, 0x3bd267_srgbf, 0.8f); +} + +std::pair PrimitiveVisualizer::gradient2DHorizontal() { + return {Primitives::gradient2DHorizontal(Gradient20Percent, Gradient80Percent), "gradient2dhorizontal.png"}; +} + +std::pair PrimitiveVisualizer::gradient2DVertical() { + /* End colors are 20%/80% blends of the above to match the range */ + return {Primitives::gradient2DVertical(Gradient20Percent, Gradient80Percent), "gradient2dvertical.png"}; +} + std::pair PrimitiveVisualizer::axis3D() { return {Primitives::axis3D(), "axis3d.png"}; } +std::pair PrimitiveVisualizer::gradient3D() { + return {Primitives::gradient3D({1.0f, -2.0f, -1.5f}, 0x2f83cc_srgbf, {-1.0f, 2.0f, -1.5f}, 0x3bd267_srgbf), "gradient3d.png"}; +} + +std::pair PrimitiveVisualizer::gradient3DHorizontal() { + return {Primitives::gradient3DHorizontal(Gradient20Percent, Gradient80Percent), "gradient3dhorizontal.png"}; +} + +std::pair PrimitiveVisualizer::gradient3DVertical() { + return {Primitives::gradient3DVertical(Gradient20Percent, Gradient80Percent), "gradient3dvertical.png"}; +} + std::pair PrimitiveVisualizer::capsule2DWireframe() { auto capsule = Primitives::capsule2DWireframe(8, 1, 0.75f); MeshTools::transformPointsInPlace(Matrix3::scaling(Vector2{0.75f}), capsule.positions(0)); diff --git a/doc/primitives-gradient2d.png b/doc/primitives-gradient2d.png new file mode 100644 index 0000000000000000000000000000000000000000..667881977d167bcb3fb60d9f96d5a54c998cbd25 GIT binary patch literal 24867 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 literal 0 HcmV?d00001 diff --git a/doc/primitives-gradient2dhorizontal.png b/doc/primitives-gradient2dhorizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..8a3c73bb23d688f1aea5de48ae226e89eb76d180 GIT binary patch literal 27596 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 B%;o?9 literal 0 HcmV?d00001 diff --git a/doc/primitives-gradient2dvertical.png b/doc/primitives-gradient2dvertical.png new file mode 100644 index 0000000000000000000000000000000000000000..66118c9c7e8a3a93cc13cfe1375b3acf6a0a4a4f GIT binary patch literal 23932 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 literal 0 HcmV?d00001 diff --git a/doc/primitives-gradient3d.png b/doc/primitives-gradient3d.png new file mode 100644 index 0000000000000000000000000000000000000000..309b38b9c90da0d47d5bd36446ee107569d60506 GIT binary patch literal 18495 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 g|Lu^)6(eyY=Y*0WoTvd;kCd literal 0 HcmV?d00001 diff --git a/doc/primitives-gradient3dhorizontal.png b/doc/primitives-gradient3dhorizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..c4c4029aab05986f1db586af2de9e6192f1e0342 GIT binary patch literal 18838 zcmeHvXIoQk)a6M+Kq3Nakcd(&D4__7pnyQI0il}EI|$N?2+|>7!Afs}^w7KX9z;Yz zq=qI+M3LU47?Cn}c;1J%dw0H- z%*kpAOut_8Ozr-&<3DE%zV!dWUx8)vPD|P9#=6(Px;4LS21lk=dAnB;6l zG0Rc%oQq2I&@}e)-;xO8g`g01Z~Rsq!8X3qaLPtE{N&kAom@T{sRDmbY*~XHcaR|X z5z0nsK+*+g>OtN_omx#1%WO?^cI#ML**tN2dnOYaJ$b)ZkwDcB3R-v0#UAtfOk~@1}f*Zs_Yo-4xk%CG$dui)jm% zewS9bnIOvbx5PtLIvlB0QjY4#+1{s5-2;Z>)69pKh7dNXcGqUwN44urkKwBwr(RvG zbWk^~%iTV8MBcnvd1kdsc-js>A8%YT<_MjcL# zdfu{;&7`YI2L#Hh1v$Ow$+R&SZCY~;SoDX6N4YYM4s;YBykf3^=l_@7jPg6_@^~r@_qw8G}x1;_5mwl1zH~~r#29ju252e z_-<&2qV9n8qj~o{y$7SCyp8nV&4G}2)?a~S@FaRa^~vswBGn%q`l(?rb!Q)>oZikq zqy8t>KYP7RjysjN`Z#=y7b@n1e{+({My+?I8@6>1*x#PCy>y)MuY5&x>$1bND|^rC zpgw6nmtjg2?l)}HkeZgXtuia)rJfQr|F+yWUi$(;IS@)}Lr}J}Qm2;3e(SZ#TbwB9&$7u-v;>iGA?kmYS24{Zyqb&e(=b*V4a*II-a?H zBlYXn*aAeeL@nd{PjG!amvbjpdWf8=yR>6|mQoZ-GN%S6h9X}^L^s0kvSbaCor(JGw3OTRF9@~*^&V6 z<8PR{&%SXVNH?c0H0ELK^130{URDUA{5E+>7yDvl8vR3xN4Kuv+Q052GbLR)Yd_uu z?4jJ414{Kzj7FQDC>F4oa5KnAY0AA36dt*&=qt_RKwneZXND0cAK8ItK6YR zW=sjUR<>+r4RV|LHPvhzZonwzXxbFj9DBQ1SJO03w{bI|HCS*iI35pEkc-AMjz(>S zZ==iVonjH;fYALnx8ye6D{41t_=Go&=8EbozHLrYr(9S_)IjE%))Tbmjnh&y4ZatP z9!#M;#}82{)j5y{$Q5o$Lsc%OFX-Z7L({MOY-KB#)XSwY|3+arw(k{)_8q znlhKU@ZI-kLhtBi_xm;qPO$%j#qF>y?_*pyVE*q|tZ{xQi_^=*2A-90ojLP`Jm0FV z2x;{E;HG1@GYcf11+{e^W8PBMFPy!Yq0luw>|M(z`sHprQfY4;4;Cyf0o|=1bWYUE zWA>cA8m+MKk;?C&IsI=?-pG8Jy3XBvmIW%wfz*PSy=&$r+e`}MOw058NIQdkp6%O^ zml|xE34$KJNIJE%icebX`?hmvJL`m|qVVR;x!=uwbs;53%y-myq5CDv5UtUYBIX>K zKR`NOS4bpQ`c`a}bMZoq2QW1j9NbMSy2Wkt>YlJw&COjWwSGyP(8_bWbH`E&SV*2; zvJm~ZB#9*%`V+gT^Ufe|^CzM4=6aylm@}2q`Il{3ul+m&Z!MD!?_8hT^}oPh%q9Nl z+9ZF;7}vis+Y%B`-9UG}4Ap4B?jxNr%i%8%3P%#zP4(Us+)^wa^ZcI^x%$5HNpqW& zlv&aFEVJ3cl>RK=as|y}`#J1PzopEDCn0b+0(7aBG|pyBEwY!gSO3DBr>2Jxzl2N! z9Ajame`+Tk>|_$qqd{iS#hf|rtb<1J)m|$j_c~z~;i?1%xp2?13z;{%J7~UIUD&*_ z&R6XiGQ&87q5aFt?#b~zA%K4*-1 z>vE+vW;-Pfy}oj)09*>>I(;qs@%`QJ-=<>4YCotv`m=2=0SiL?yVSP1(7^{rwj*Ax z zioQ8^^z`3Qt~}?pD<&Q&&I_@v9kr;J*X`obkI$|Q%B2xcfeddnmW5ZfMD?tuy=HY^<8{ z=h)e%sAQKRCUZrm9>(fR8H6)gx9LfDO8(~fX`p+5xV@=n!r-L;z4h8Tn8j`fI|Mt* zyf!aMIhAET{j*J0=3)-&z_hqnq{|>v$(AG~nz53t?_ebb6ORtIy{K~VGY$?kzEAiw z#b@BZGEOi230W*!QmRL-bc#-lcpBb1Ox+BenQ~!=3XU<80T5`1FWubItxJn}Y8F5> zF20l>wT9@lEb3H9^OR9*+>+OTh1g=2cP6?$oeHl8BFBL9&AAXUS zfhL;#(5W5!$xp9)(2Q1G%-+g~}ih|;RZXRVe2{=nBIMA+>9|(3q zpJCoE^^gA|)l$H_w~kVWp_4m$rg|$|xf#l%Yqtt?#p7NNJf2@}F5dvivhXRsv1MA9A*>nJ5hjtNjYzcgsO|` z>cfC%KCc-*O0Aknu5;S15cvH#K9H`#Li)l169I?figEjM^tr63YEj~VrfnS9$lg`_ z0#}ifQG4$hpUY5?ap9)ttwL#Q-oeIKp~VVne9#pYn4T0H<_Vf2*GlTvd4%-PHkS!P8ly{BZ9OPbeQ{ok;^5=HKtm!O^9 zP_J|#Bqt6I*{&|t2|QseU&}O{ZX0vY9{2q-^LC@OvSQiwnQt#z^;17Nb`wG&bABk~ zHfH(bZ+X0DWk;S5S4VpMEPK7_;rRkhQnD?9O1=lSfy=GsTj?&C{_S()K-HXL*CXF_ z3C%gllOC?`Bj?0-0TCYIfCch0kJ(OJQi8k$^OSDSMyjzWIvLNHt~s*e zh0hcCqGeiAl-2Hw+|O5H@5)oRUHAQQ z_Yw;<&W=z}2RF*p%;1?3ZWhm;-rVM)pVN6`c3+eD?zY~WgHhzLP%FuNdSQ^5-}_{~ zuJFfgUEehNen3(2v2aFw(FdztUeLL9F8Z0>Lhx>umZ@}ezjF*2Ei*RT0`jI$-xspL zENilmSe`WvJS}qo;X&mY95>Rc1?Lg3Ns5~aHgYg`A-R)k6{d&UH!s$qzc=5 z=eb>P2+H<7+NX-hKl*IFpy7IvntZljiM)sml@zytSP4CeSE$igI(U`+V zN$y*5@y*=q(Bq~BBM$vBvL34DDOKJTXXvvqnk3^! zV#Y8l`kzb*Z$H=vd?RGW@0VP&aHtqOqih!7A_p-EASD)Jal32?1>HJx`(k#P$~6Cx z^|{1rfO!3aFm6Yap+j$v-jt{}ZPMp0ONL%wXur9pVf(x)=7`;Gqt}CHZkh)~Wi+}$5?UyW znr+C8huJ@ES>(n`>c?UkT?YeK>9!iv!%i`l6n=fvIVQJ0@JzF(^qh0kHJQe{`RDp2 z4Y5W^m~#5{@h$I3#>NB;N|-k9V3xZNoX;O9J)Wq)=AGPRUh@TTX=)Z!FwNxcJU8Cl zx!VSnMm-6-Z?y7YdvwGgNAai4%nq4ol*D;&UG;_GCMPWmK`|nlv9bZ=w6=21_P?I> zFf%qjJXXvq?Qj-Kg+Ufa4+edW^|49e@7>urvYl0fQ&iXJ8GRT%WWKe?4n6g{44pn| zf$5RZhra}n4;{TNJa|;5BJE+`9eJ|`2DzKFBZ_Md)8HTqXwnm|aXJz*>9;rdwhP{v zG=ET`j?$xtQXfXUu)|<oN1PnM%!ltV)2O=(>dz z<0taQq%v#DZ7W*!a>l3b%E03%&7h(%QBwujEYQKR)c>AK-(1s$Bn^5(h;EKp`PWWu^OYfI{$ zKT_#vRFv4K=~t}m7}6LA_x4fZ1gp5JFd^o}P^7jYqRXYSi`y4~QWr{P|X<%xiKpS!L`c$v_2P^KZE(<<>ZsnBNTgfTg421a$mYEcmA(RW)q+`x*XS1BSR*Oq zmCaPYI#Q$<>(=^w_c4Oh9tyd#A(-D_gba$AHeE5xN^^W|FD`vZN5(p;lu(rcb05#` zhUWB_kJ8fHG)dARF6SvS8m(23lMD*Enu02#o2*H zeUYFg9VpB1%biagTDezQH@+DQq``X(^BPcV%|Lrv%svU)$~aj!?^{B~E2?!2BqqE| zGT++un|L6Nq~U42>@bnz%qFS3v0*QC3bgL!_sVP+VZQ+sFZnYsFG(;E_=$T(%XAPs zm8MYaGT?ea)X3|?3?PfqA1g3{z*rXOS@2dAobIVe(f6%ALl6X6NgplOOIAkxVFdZ$ z9v5R2Cz?gGI8ugE-m^DG8W$>C5i8I9isRmW#tz%jgw-6fTeGBW+v2H3hEmfZ-(0mk z0eC;Pl8i^g0Xa~-4+iyfVVAaI!aQUvDr<}sH9id_PLt=f)ccY-V0W}&Te@u49U{R^ z$C&+_CUSpsYj);|;A;oc&pvAgVUPf>XxRuzCE~^j=MtxZ=k`8E+|e0Qy&s>4hq90o z9_nU8Wn^gP&L{^hxf?Pc-al|6-soc1!q*YLBG!#vM`;!qvqzDyQLxAA2!L%vsnj2=>R`7dA;zBHuFz8egXvVV$((K*GF#Ud3 z&YK_@cW-P7YUWhhD|N_usfK<@_8l@R%9$vyJagfOV}^^ri#(KoMedul5?D25-O3d) zE~+E5*REwXQZl7lfJ8T02}zUlg!>oX=EhqmVM>8Hq1YY_swek-lu4fF?NgrA@I8@* zbIk1X(6WBE_*A`i6-Gi^tf#^VUH*bS)vY8&(aoD5iM;N3VS~#>+`?gXUk}-h?%fn! zWTGTBp>*hzN}g@|x^6(cS(h;NPo|_t_fws(hkbsOdqWc1sM0}G6z+V)-3^3+UJ86G zQ%YA_BUky}Xi)Yiu*8;&Yz*(UbaQJp%ErSe)HvDqZ1YX6_rIo74%ptg^m+gO}1*So4B*R4mAo^{M7abQxLyLuc3vY3t=Na%Wz>->yFknUdd~la5@8{bP zt2*Vi@u)l7!s*(MVRxoeZV#n+{0W5!;P-=hmVI)@=`LM)X54Eo_nv_;Z;@l1GD+^n zRy-L!_3*x~*Ic;$r0??eszsT^yQ}2`Cn(EUTrM}_(PAvcT>o{1=l2)KqYj<d$~iQdzcH@-gruDj$oq$kNXJ+)T~QnL0l7|vEt63cKl6P5|O(Yuhj*)y7LtHm{! z(mJAVzBQC`YNVPUdXWgn+*OUJo(--&G#zb8`D1)xAouxf-|MFPaX?NEFSnA+%s8)~ zg*ep@?vi7iQU|!X8hvH*2!D9Xru{@9eJ@!f5Mp?WQR07Q2CqcXR*YX*!YwR^b zZ!B!P_(I=8B8|qg$LwJ{XmD-itXirggb5F$W47ei<>j&lL3*w>!)vX#k^1JF)eQfq z0#i3+vtAPkhK+EzZ9~g(VycyOX=Ys_TTZbcfgvujVTLtHia^pOh)$$NKU2=i9lSRh zH=b>4gG#i`QIe}+_cqM zsJWDM>(tKv!yB`#*t|a(O+s`1zvvFmm#u66w(T~b4FwV|j>%_L5|__f%v9{INGXsi z%kRmZugf@m>OkGnXc4JC8@hRndCluAMHTGs)Xl8}{e;i2I%T!}^nx@TdwwVvZGKbg zJfOAM7YY%xAuJhEN`=!m@U)h4-C1gggH&;|)M=1ToxU-Mj6?%vM76e41nW+p01Nve z@r;hOMnqgex6*T4P>0Nh4w8ZBxi}O{8P~a z(QHV}fP7ZB+UDB7VTU5cgpwuR5B1*-f1RK#VR5op(yQme>VbmGB7S*w7ju|R2mXm2 zb*X0ZwZZgg?^S=)u}uyBLoK69+ccHPChoYBrAL#d0ebhKeI6(`|4A%`$2A8+BarJL zM$!Dbi}Us}f?4XGj+s(h8~1UKVM~3irO}#@fOg84hQD%x*NRuBGDTb!pu!DK&L}L7 za}ZHdhnY68AV7)>EcA*3+=6?auH@)9`xQG4iB?jz7yKe1L8hDJwl`u8E_N#r4&~;D z!pXbgh|mLId@be4Yif<|_>PpjcEr2yK=CA9maS%(wFhtu=Q5i12t#0;HnSX5DD^28 z2fXr5y_B&=9a*z$rt_OswK2R)p20($16axl0!hH&(7RY%5b#5v&d5IE+eL9#bt9lKqkU46v5|3>4N1cqiIHjr_UfacP{0-iKkke7~?+BS3G-EX)gg)C)?`_eu&^&mnU$ zo-dox#@A4^=V+3Z0MUfif56?~DR&)M`6a)b-A7VuI$^Y9dp{m>7I}G41x1NU>uEeh z4->m4t&wNEfAqHaA3F^iBH``lE433u1Nztj#+dkNw^D!NYD5oMNjsYBB~7$(g}317_C7dZ?*W{v6b+p`|b zc$ntJNVqn~@zZTMJ~qTo(-qAu{m&my%)HZ%mbT_Mc@HC5Qfz{lg-q)Xr-gx~W3ZIY zyOm@pJrVx!T`XlT6}BOlPZi74jP@-!*9DT#covinY^C}_r6%bPU@=?{6sa-wG8KMY z5SfOt^TblbpJ(X0`DnAN-kp+L*LJD-A{HzHx=oVf5^4H-av}koy6h59ke~t%ONpG! zhK@FA!9Fz!19%96Zje`OE^*aipyHcr$K86t2oRF@;n#E3H3PUj=LG{F1w%Q|t*+Z- zXh$7(wTkbuL@F$$L$SC}EeG6~>`2Z_pM!jS5Zpts$ElUnX~J0%3ASYbZsf5o#dcuyW>2RkiWgbF9BLP@HdDNnSHd-Y%tbM zn4y^ptnb2cl+4E5U{Uo)M^H2Z} z3;QRFv`~#WTFm59X;YxoKie15G=HxCM<8jE7izM^xW%@TICe@7TQC9+oc!fI82A~m zS%-)O|FPxo``F7abJ|dxWA1MT1`rvjeUCF752=Mf(my<>3S*0dClvDyFX_YM6`%&g zv&H zq_xPxIsk@WM8jV@)q_~>K~p%^DM}#K98)gx71VVk?CK}a-d7XYLn0YEb}6vl$?olr zZJ5RZ*JUePX6fhFXfPK-P(jOBPf%Mqc zZ1ijEJZ?y9%zfQ-3Lj)*`6H25wr6`VqDUeB#L{LZl*NRgQt&xu*}y+&in2aDD3L$! z^-MXCay)a?Q!)oZ;=8~$U0_L>^njy5*1_EH#&^UGZ?F=e)-31*fW}HJrL~$DUR8Z0 z-}IhCuT8+PiCa8Ui4DP%e>g4lKO`+b-0uE(;6w`ip|5;t%d_Cc-$!XIGVL+4-y?{G zUv2%HWs?s9=oM697-o|V&>jW)1tWo+7C_R+VFFQLg&MHMouf2<>E}F?gwS7=<(UHy zq*`tQJbUeNuLTy@2EL>VjmUxyDyYB=4q0znQdlmWLd%T`hLW!gMWkS#tk~%;HyW}u zR`7!m25n34@|R$FZdja2J6VQEx_u%7&ZHr~Jo^|{tz(m`89#8!Udy!-sH&sP7Y9Sq zUdHOn!G6o}{AGhMSR`Eye+o-7CqT2o@k#K)&dV7;5Jm1P!YOhk<44--L27Ig30Aty zR`br5q{X=Pc=$Unv(re4Ho%1<%)VKohFo=N3aX&Y4siP5EOK9yB_$rXBk+UhWWFkA zRYBykFN*Vtppw#k!R55pYz5WW#GZml?B11Np6p$C|0pllIsuNw(TGt0AmU#dM(D>A zGocs6-Z2@O(>K_w?6)hEVBa)hFDm#gvRX-x6oA}xKTA<$tmqYdORDlIn&fNI3ewb9 z(<~QN&%{Av>MMprc0pM@-iGeXF%5%Klf^r?TJQr&l7+jiu3|xW@vkY+7Sv@!X$V&HsoYU3>{H7YrHw2V` z7u(SS?@wb%uo9+XHO2f7!S`iObA3+fFF{R!h`nfzqDauzHAxt%z4qSRPIDb8l0cGd zt!lQdh=5~+kP_DCwejR31;kd~MGf7$Tr<`2wGr^qwQmwMrN^+wGDgQnz?(pdNtqE) zhxM@~fV}1JI(m!Ook3Ur-$SJ1Pcx8MBNBWEU|9Ps<=gk;3?VKoFX`mhK7b{80X2HQ zC*NW>8`=S&>`ly#s=YfR$h+VQ5=qZ0nlk#$!hOYQaK$F+G>}R5F`rbGv=OrE=;pmU0Umqa*wk90RDg9w?ov z*Myz5C&!~S**)i))^7iYXo@8+)dT)I2LQ(k6)|`zvyuhnp9DY7UWOL1o(pzWgy!wU z^mE9}U9(?#o`bJz@e`D|7z#6Y7%PE;T|LN#8a3wzMF~(hfkdXM!nQ#DO?l*e$7>8= znLeLTzRy>_@3Cu(6dN4^Nui8LT5CG`b#4_ckhJIQ!^WkMbc!BXPb^n=b+a`6!$On* zuuAR>juAM`wI*A%WK#*0WLH!g1vIA>f;g|dPRPDRV!x~1of83enq7tIfHpxqB=kjrW) z&Y$a)Iii-3Z<-pr>fip%%}0VRJ}jg(&>$gO;&wgZTm1j6pRHbPjy(#Fspq>qxZH*- ziNBL?v`1X}$zK3-cnM07AH(FAn4W+}fy6n-lK#!W`*K*)h(3~qj;9^8EtrqOpEK`q zMMb%YF#jI0B}LR9vZDc6AqR_MaKvl4wd|eB6tuwgc&4Hz%(T}aI<`yW!?~G=#*yuO zT3Y=f%vB&7=9%cGi2qikkh5+sLx!@=xsIoyEzGMm8l&=yP5M&teP8(@_XICTKo|S zCzRVO5cgP;IA}QtAiYnn#=JT6_-71S(P{`W6A9qQd>RQF0H7@11ytjE-QlTRxAX*?b{i=aZ&Ym;lwTmBa#+$*KhH2e2wg@RiJ(uzAfn zX|=O}1A(?`z)UCS!=)TFd84W>#f_KodE4m2PqEeUTQs*6GbK7Q3iu>e0_k=Cy*fpp zoe!SMfj*L<=iQqzLdnPHL4jeh?cnxlxea!;kg!)<__W@~Ft4MIdoaFCByp?)Uu1n0 zG`gnqX(TFQ+#mAJJgr>mo@d-wykP{Wt@hA|J=ye>KpNYTk>{KMrZyZz6_ppRZouX- z(0d}3d~&EJ&|bA}2BPhv1t|ZUC!}xO&skUWF(pIHAOe94YJt(RLOf!-HS)9w23pY| zZXc_`)V&0I)LKc*GfZ@!g>yEdjC?;j$ScS9SzfY)<=RQ4%DNJY^YuDq+~X4X+~2X7 z9SaShyd><3nSSy3D3WUb)5WKebl1QLG6afrVMLCG*9b~^t*Y?rqw&}JZrO$^8^aq3 zZ0JG&I9WEkhkMnZY&=Yq4E-|Xn*U*yCT=u0AeN_hZoBq$JFpm_i?nCupyyaptNnIv z8eoNY&x2DwJt2PnnaiN7HTwX3%s<^0So0yfh;1mFp)W(yv@}7eC!9onkgHEy;umI9 zL6xq-1TaLBHzFGv;(&H5b#qM#nZMRGZGu78YmA4x3A!1!k{%oFX-J1Q_8d<+pk%Y5 zaB_;yY%NSiP%u2D_gdb0z9Q5wyhX$T2KFD`K}7`JSK@djjg(l;r%{Fw&HB3JJ7T$} zeN~$m0PvH(C~?40sLOHIO;1*1fQclekq7NuuG(!gAk zBIA(GB84yw8OrR@@P}9Bmw#=k>weZM(C+S@Pp6;xJv&%5 zE_OVM?-X)h2$}}wDzz>gvUznyJd~W<-&i-)s@t*%>SI!KvHy8kw|l74@&q&mT@Vug z3hq>`n@5b&xVPzOzr#BRN{uy9mXv@K(rnZAXDRW38t$mU0^J^>1q869@Y!H~jif40UHg6B-ccoti@!roA1sB*W1M)WSoZP@E?E@Fle?dGwY*P_jzp@4KCMcMpPT z%^L^|DBC;-`b+yS7O>AN@)xIrsqsLloI)Cy$}h)7!ACBZu&aKVD*zJZCmxs>AUgq^ z)PL4?B{fHnFY)YtkF>f6m|F$rA`e}c^_z^aes#Gdr|+=55!d`Un(`dnyn`a?l`L!n zl+Y8zko1g!gK#YAsUA|ioR1#6bzHZ*J72l4_(&4SZSOTFqbeUC>-z`v6xd;A{LEL5{M3gdWcJz^VB*3&3ZC!=GyQ1ZBlfd8 zgPLp$09_zJellm2SYXDS74~I^1sK!P&4nbugZzlAU7_~|j*!@@;RhW7Vd`nc`@NYEt&j^pgk}q9xxCdk? zuCe}5*GQvB@ETjzjxhd(B@`Mj$VK53D99Oq^P2){p;^78Np=P9|M~YiC(6R>fK)P z#BB&o@daOS8+bRMH1dV@lgMXOmtwg58iW%>fj@ozjmy+bz;WM}_? z#oBmlk88a!eGjA17>hRJW8M-K*aOcU4H&b@4=rX#l-t{QEGcLHi>9}Zd*ZneqKSAghjby!pJ^jV~Y1U%EB0ptWT%= ztVXJ;f3smpK!*IOs>;_QjC`sv`}Elzq$<#{CD@r(1s;5x>t65#U%vd1#8q`PrU3l$?EP5HWL27M~8 z*}G5IJpwXLh7N-B{G|?i#$x&-DJ=ex6RPwK1xxv%`msYn@k}ULD75tl$W|iE7k+>e z?jp;+$DnuxoNtMo(fWU%+|ZAPGv)KqALI*Hs=YCd+%eMmxdO7wUMc;L1g&U)h{8Ia zVbUyqp)Ed0?W`UKKAs6Qnh`6kcs`yeBH`@_>?=3-6v!hHLd;f}o|;yYng@J79YER@ zwXCrYnnkHZQuT8+s%V}@pJJ!T6*I2mzp*a8Ugn{ zi*yTuyv4fn>;57=@uOzOQ+HIg1xlE1f`$jK`~V^`@36pA!1MqhGo_AO+>w)Jc$m9? z44kPwD(%Ul8K@q;7oYwZqXU>V8u&ZApZ^7!7L0v>o#zzti3AZ<+TcqYx1P*@D^Le>-mUFB}|Wh2SOYKMuFG+6w>=Knv#R1>1g4b?vi+?m{gq8|X-x4D7$5s!!tH=)C{sWxI_+0P-A{!e25B5o7ul#=jOSuO`tOjg{ zXjs6m>bcr?%;ym!qCcZ4KvTWA$Y%FxZwE>d@ZJSbDe z^YX+J`><1nU+2E(TL3Hd7hD1x;@qkvrJaF4O<0Gr>5t|Y!1UadU#@SPbch@{J(E1) z4%C2u6r5=dPb;GVt@Xi@LJ{4!`I1qvS;JDkLs<|kkHyRxl~2BVSAlWg=g~79`pEWI)qKNg`k)vIj5GyBBt3cD zqX8Q%Jc-=rxDaI;!jR!xhtD3%tYLS#2G0@#pC;^(oa@trd4|Dc;RLbLviwy zFJO5zo-?p)a`X}bTb4J7dHYq4J^hV1XHU7O^k)~4}@dLDWuTR zgwoyjF<4yPIDr(ZnI#-xr_Qe08({li_~X(T;SUPHq07@r2=%K}&k>@fyDZ>Wdj1ode}kSX_tq0>Ap-tK%MQi1d*LvvOHbdax#rs~t} zRwMrC`QCgBP@Dwuat+04)JpPuTn-pDCi(qztYcs?~`ZRr>K@MZ^qTI zD-x%d}Q| zUQC5Rdeg%CZ|Sz9ivslUkpn8CaCs0=(Bw;vnf8@e1#-|so%5V~cWg)cFVs$65wua$ zS;b&+I?qzns&dyRY}WCky5qlAvMG~UkeShc=^io2x*U1(J!9XekeI~M-C#7%d_;CY zB+uGiulvlD?-XcTx8YhmfTem2L#!UP5CN-SCPTeq>B;abM^m#x%IrZQ$Zm!aApfp0 zh7MjWGh$>>4wlb&?3uj^vTInufe|$AN5>gY)%?WTjQGC&;Cj{1NAMG&=0%oaZaSJW zoeW)LoMSZnUB!z~Yt*u~dfkQ4Ge8eD6pRC!QsajUF;CzvNTDz=COy4A*qRTN|GpG7 zZIV+RC|8q$`>N~lS(n_^z+E{NqA5;oxWESBSkkn>1XvOMdRag9zvovx)P3KmHfS)Sb18rb3gJgk+?Zkkd2jzio zi?}ViU{KIgWmIpJ2EwkHifG@g;{z;^F3&do*Ov4TuQ*s$ z1DNUdRF}rD2lGlJ{cS#1=Y#k67D@$g7`~~x1u-$*MQMA0O0C1yMjrwRjQ$43>ZJXC zzB(IMQC>#{S2Tb~qTwxY8;FEmNy?8&^XZpynWOR%nLkHv>dqDxewKE$@>w}&M#nwL zg36R$!{^I93$zH|Yt$5JNje{18Tjf9~=xo+XUphV*);}ZbnWvW} zTQvJL(C?~GZ!vfQPWsj|;-NQc*(gJaNYVxEMd5S$gXiNnPcJx6ZvZqlGg`4g{&s=a zuLM(P9*rV4OE0OOJ*U%=uOQ`U@|U+u^*i>dG2a;dni(A`9%alx7vH`xO(5~c7R|=# zC{(6RMeo02!sYZEZ84$`&%8R1PkZ$k*1YVES)S?G_AQar4DF5;{)3Nql0B=YOeDkz z`h5W}oc%r5><%sF($`8C)=wMvkfHGFwpc$q{CzO+^}2c;P8Ub+%d$$d0Aoj6U=TKb zsn^`tsv@W-f30%?jF`L2@r2n)G?1e-{kWZG_0L;g4NPDW}Cr6rn6avxa z_JN9E$;W(H17!=q>19zRYYwff0Y0M{?`F>E+G*?AhDwz+SaXZ}Lj_u}%}{4o44C9G zFh!LrT)2kaz76_9i+l~Y<B{X3PMwCQ5ZkiRYOji`DLF_+(#;ax|i74WIV+G3=6o z*IayT=$evkepqUOUJF+!7;)VS8ze8skj1*4cUryZkKi<-;C5@3;@L|HvdGILa-yN+ z>r*mCa*>NbCdP6jKoNBZpC+?`81sebhBL6nFHyN*bjhZB{X_P7Ls=t$@mdDP7rp*U z!D)X$`=PS|bR_#bb*7?5Pj8o(egmik7EsTa!wHBEf#b|$23s$`IX$6%+c}w~;gx%H zDyF~pHQJ`k=}X;@{?NbcFitlgdCj>bERf45M>i)UVr0B;aon&G`vGxM&;saZ!66%X zTCyVIiqqE|eTU3-AM>V(v&K5bmRy(X3!hHf)O&wNfKp<_fRqjBA3q{r)zwrrjjD>T z^lrfRcw=!A1BhcQ_%v5wNK%{ioAWLghu6K~k{?VvnH<|CC7ohl5Kb2sp3P#pE zk8wZOd6R;M+J1+D8%LRTc* zUvDIxPc@7C$eOzUjxalvr&KCD{Gko^i-&njDX`{S?#q7tutQlU^Mu&XB7Q56nmyaY zLjT4>oE2D{d-w{G)SlrUBX>oto{Z24OL`uxmjEw352~uNZMgS9!8T2jr1ew!!dwa_ z-ha`_J~$~?U&J~&Szi_U$az8^hWj8i?P;`|IBGqOwlKaGEi0&N9u*i*m;jk{GJtvC zFSLM136skQnKW*E##-v2$&Ij!d2W{4>&5$j9F;!yzz>W{5qz@|5pZjt82Fgi6*c>9 zhSvS2;MQ76;bL@+es{-GKxK{=qxbT`fNWRi3ErLFp9JmP>vRA4)C-#}r6_Tej$G}I?TrA3YY%4#;A1sQg}A59Tjr<~AX^9b6o z+%CSTnOea;Ghi2r=l+ZxAL*p=LEa)rmARzzIw-e7XB@k#ea>0W@s&ckdBzyF%6?E2 z%M?_~7GpLVk)YLmy5?KFOjfY#7+MKFVrUzxJC$hd#sT@ajZRfG@q$59(8PB=q^2V! z2t1YE@cc?PZZ#W9C$LqlNzk-bGuAXs!`^CL60-Hh9Y~CO)FKZpo1-GWUCQ)hi-12I zdHqJMgEz7Fc4V!KG&1obQbJw6boY61V8Xqtu6lRuTwRO$&T1Cu5j$q4Ex^};PEkX2 z@1Y*>g6i2K;iJtNe5!IHvhv^1cGG}|vY<{eX7_u7%jutf_-0+aVeX+Lv|>^sT&(_K z*2C!N7y<%K;G_5TaYT~1NIg{~Z+fdCkSBVnHyhW@0og0n2@e~z;g0o%&w$BX1qb0< zpS0ugzuxP}pLekZU(Qxo+70?vk`lm1M;@6x(A{y)-ZlB_4~^h#6$QOt&xeo5y#o8>3PnQ7)N+Y!^eIG{Vm zT=QShwBP}|?UuyiWHH@m{P%PHcQR0~H67s~Iyiq~Nnh;)#5=*$-p*vHNABK2FgzB(80Dd`?Q%(e)_<&M-vz27DxK;l+H^o6qWV zEt$1mUk}o{(H1XR!7(4wobifN53nk@HE)>HVG@r4z$v_f{2(Jg6^*8GpKlXB7GEdm zEbj8ho0xW&KswEz19|Z?H(c6@N$FG{Vxe-$exKI;K0p>eduD#+`2#c!37TyNH5#>>quMypRO1FcjX(}`^yP|5Bf;Ol!V+%MS2U4j=Jxsb7znIVql%F z<>IH@*L+W|Ar9^&KC4|#?mIs-lQ1C%MqZQPWbs{2PMU5D$2-Ak8?}@sJ3E~|TAHw} zIO9h4fn+w91u$~Tr$bhf!PD!u;M*`Su#~!CrfpeC#)_prCI@D6dH~G3b?Xk!Z%b&fe$gOxJByj^( z+SOM(fu?m;$V%0dA0M5mjN#$nfD|-g4GqHdNMfFEE1^(cV*!6mHfOX`pK*l=ihFIC zbrE$~#uqTRg)N>7SzK`=ruBk5w<4^Csuw5}IO|>AEfvn5Vtjxp^F;qe8I|RIXGJiyzr%FZwcY|TB>_ehF^F7&xyj{dmpOTuXfpX*%?7P8{9#; zeUKKYCtqwAEK+n@0pWKGRQtfod5sx7H#{!KDoPjC9Ubz1+;wC{7fhNnuz6J&N!K!q zZ^u%~du{SD@pVVY&VQX3FCjO@kSfL(ko4~#MV-rZgbQo+M_Qxbbg9O*wa7R9KtNaJ zkeHf@yQpQ)EaH9DxZqCTpLR{410s)yootAP`zs0)!6ZC&u}(89<*0tw3!s4_(e`Cd zezDvN5OfKUQkPdM{L0-zl}D%a2Sn^`RZGBKfWm2^TuS=*8Sa_>XL@ZT$~u8}l}4V6 z`!l|h28U z#~3diJ`K`=qS`PFm2(vhXEPQA^NtL3hZ0AJ#nf*N9NqNaQ0ZHMlg7Lmhbr|YSJs}sJW~D zuMsS@zL;Zig_j?K#MP=tPF5NFxv0Sg`92ZxOM)_|dF?TEjl6ELSjx8Yy)}3Iqo%@n zy*Ib7Qi%X;^e_&H#7}@a?T6@yYBFTp$1^YyHJd|@|4|@6iuSHXTP#F6HFE0bFSISl zQa#OVxXFbZVW&~v;EhHL)bffLmh!RcuFUDSikDw~lu1b-XZ7CjRV=yDZXBv}Syo)F zq@Sl7ur>4^592dYhna;HL@q=P$ck(WR3 z=xAF1TeARhQS*aUmNKUW|ESw9w8$;(^PW}-Hq*+Zra0vECHLpopPsw`VwqG+ATIl*~vd|WWd3sfwo(B&3nIM73E{fHoOfP9g(bZAbCJcwGYAT w_cPMQ;Qv4AIKun~{2vYf|JVP86DU~Qtx>NPX$mjbVLV;+hUWF+s}>>u3wd8kB>(^b literal 0 HcmV?d00001 diff --git a/doc/primitives-gradient3dvertical.png b/doc/primitives-gradient3dvertical.png new file mode 100644 index 0000000000000000000000000000000000000000..1f84fc662c92a56c80fa92e746d11a2813498e95 GIT binary patch literal 18183 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 CBW+Xw literal 0 HcmV?d00001 diff --git a/doc/snippets/MagnumPrimitives.cpp b/doc/snippets/MagnumPrimitives.cpp index 4ac9da13e..b0091ddf9 100644 --- a/doc/snippets/MagnumPrimitives.cpp +++ b/doc/snippets/MagnumPrimitives.cpp @@ -23,7 +23,8 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/Math/Vector3.h" +#include "Magnum/Math/Color.h" +#include "Magnum/Primitives/Gradient.h" #include "Magnum/Primitives/Line.h" #include "Magnum/Trade/MeshData2D.h" #include "Magnum/Trade/MeshData3D.h" @@ -31,6 +32,25 @@ using namespace Magnum; int main() { +{ +Color4 colorA, colorB; +/* [gradient2DHorizontal] */ +Primitives::gradient2D({-1.0f, 0.0f}, colorA, {1.0f, 0.0f}, colorB); +/* [gradient2DHorizontal] */ + +/* [gradient2DVertical] */ +Primitives::gradient2D({0.0f, -1.0f}, colorA, {0.0f, 1.0f}, colorB); +/* [gradient2DVertical] */ + +/* [gradient3DHorizontal] */ +Primitives::gradient3D({-1.0f, 0.0f, 0.0f}, colorA, {1.0f, 0.0f, 0.0f}, colorB); +/* [gradient3DHorizontal] */ + +/* [gradient3DVertical] */ +Primitives::gradient3D({0.0f, -1.0f, 0.0f}, colorA, {0.0f, 1.0f, 0.0f}, colorB); +/* [gradient3DVertical] */ +} + { /* [line2D-identity] */ Primitives::line2D({0.0f, 0.0f}, {1.0f, 0.0f}); diff --git a/src/Magnum/Primitives/CMakeLists.txt b/src/Magnum/Primitives/CMakeLists.txt index 7fead0fcb..98e2ab79b 100644 --- a/src/Magnum/Primitives/CMakeLists.txt +++ b/src/Magnum/Primitives/CMakeLists.txt @@ -31,6 +31,7 @@ set(MagnumPrimitives_SRCS Cone.cpp Cube.cpp Cylinder.cpp + Gradient.cpp Grid.cpp Icosphere.cpp Line.cpp @@ -49,6 +50,7 @@ set(MagnumPrimitives_HEADERS Cone.h Cube.h Cylinder.h + Gradient.h Grid.h Icosphere.h Line.h diff --git a/src/Magnum/Primitives/Gradient.cpp b/src/Magnum/Primitives/Gradient.cpp new file mode 100644 index 000000000..ab427713b --- /dev/null +++ b/src/Magnum/Primitives/Gradient.cpp @@ -0,0 +1,99 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Gradient.h" + +#include "Magnum/Mesh.h" +#include "Magnum/Math/Color.h" +#include "Magnum/Math/Intersection.h" +#include "Magnum/Trade/MeshData2D.h" +#include "Magnum/Trade/MeshData3D.h" + +namespace Magnum { namespace Primitives { + +Trade::MeshData2D gradient2D(const Vector2& a, const Color4& colorA, const Vector2& b, const Color4& colorB) { + std::vector positions{Vector2{ 1.0f, -1.0f}, + Vector2{ 1.0f, 1.0f}, + Vector2{-1.0f, -1.0f}, + Vector2{-1.0f, 1.0f}}; + std::vector colors{4}; + + /* For every corner, take a line perpendicular to the gradient direction + and passing through the corner. The calculated intersection position + with the gradient line segment is the blend factor for the two colors + for given corner. */ + const Vector2 direction = b - a; + const Vector2 perpendicular = direction.perpendicular(); + for(std::size_t i = 0; i != 4; ++i) { + const Float t = Math::Intersection::lineSegmentLine(a, direction, positions[i], perpendicular); + colors[i] = Math::lerp(colorA, colorB, t); + } + + return Trade::MeshData2D{MeshPrimitive::TriangleStrip, {}, {std::move(positions)}, {}, {std::move(colors)}, nullptr}; +} + +Trade::MeshData2D gradient2DHorizontal(const Color4& colorA, const Color4& colorB) { + return Primitives::gradient2D({-1.0f, 0.0f}, colorA, {1.0f, 0.0f}, colorB); +} + +Trade::MeshData2D gradient2DVertical(const Color4& colorA, const Color4& colorB) { + return Primitives::gradient2D({0.0f, -1.0f}, colorA, {0.0f, 1.0f}, colorB); +} + +Trade::MeshData3D gradient3D(const Vector3& a, const Color4& colorA, const Vector3& b, const Color4& colorB) { + std::vector positions{Vector3{ 1.0f, -1.0f, 0.0f}, + Vector3{ 1.0f, 1.0f, 0.0f}, + Vector3{-1.0f, -1.0f, 0.0f}, + Vector3{-1.0f, 1.0f, 0.0f}}; + std::vector colors{4}; + + /* For every corner, take a plane perpendicular to the gradient direction + and passing through the corner. The calculated intersection position + with the gradient line segment is the blend factor for the two colors + for given corner. */ + const Vector3 direction = b - a; + for(std::size_t i = 0; i != 4; ++i) { + const Vector4 plane = Math::planeEquation(direction, positions[i]); + const Float t = Math::Intersection::planeLine(plane, a, direction); + colors[i] = Math::lerp(colorA, colorB, t); + } + + return Trade::MeshData3D{MeshPrimitive::TriangleStrip, {}, {std::move(positions)}, {{ + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f} + }}, {}, {std::move(colors)}, nullptr}; +} + +Trade::MeshData3D gradient3DHorizontal(const Color4& colorA, const Color4& colorB) { + return Primitives::gradient3D({-1.0f, 0.0f, 0.0f}, colorA, {1.0f, 0.0f, 0.0f}, colorB); +} + +Trade::MeshData3D gradient3DVertical(const Color4& colorA, const Color4& colorB) { + return Primitives::gradient3D({0.0f, -1.0f, 0.0f}, colorA, {0.0f, 1.0f, 0.0f}, colorB); +} + +}} diff --git a/src/Magnum/Primitives/Gradient.h b/src/Magnum/Primitives/Gradient.h new file mode 100644 index 000000000..2c288ffc9 --- /dev/null +++ b/src/Magnum/Primitives/Gradient.h @@ -0,0 +1,121 @@ +#ifndef Magnum_Primitives_Gradient_h +#define Magnum_Primitives_Gradient_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Function @ref Magnum::Primitives::gradient2D(), @ref Magnum::Primitives::gradient2DHorizontal(), @ref Magnum::Primitives::gradient2DVertical(), @ref Magnum::Primitives::gradient3D(), @ref Magnum::Primitives::gradient3DHorizontal(), @ref Magnum::Primitives::gradient3DVertical() + */ + +#include "Magnum/Magnum.h" +#include "Magnum/Primitives/visibility.h" +#include "Magnum/Trade/Trade.h" + +namespace Magnum { namespace Primitives { + +/** +@brief 2D square with a gradient + +2x2 square with vertex colors. Non-indexed @ref MeshPrimitive::TriangleStrip. +Vertex colors correspond to the gradient defined by the endpoints @p a and +@p b, linearly interpolated from @p colorA to @p colorB. + +@image html primitives-gradient2d.png width=256px + +@see @ref gradient2DHorizontal(), @ref gradient2DVertical(), @ref gradient3D(), + @ref squareSolid() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D gradient2D(const Vector2& a, const Color4& colorA, const Vector2& b, const Color4& colorB); + +/** +@brief 2D square with a horizontal gradient + +Equivalent to calling @ref gradient2D() like this: + +@snippet MagnumPrimitives.cpp gradient2DHorizontal + +@image html primitives-gradient2dhorizontal.png width=256px + +@see @ref gradient2DVertical(), @ref gradient3DHorizontal(), @ref squareSolid() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D gradient2DHorizontal(const Color4& colorLeft, const Color4& color); + +/** +@brief 2D square with a vertical gradient + +Equivalent to calling @ref gradient2D() like this: + +@snippet MagnumPrimitives.cpp gradient2DVertical + +@image html primitives-gradient2dvertical.png width=256px + +@see @ref gradient2DHorizontal(), @ref gradient3DVertical(), @ref squareSolid() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D gradient2DVertical(const Color4& colorBottom, const Color4& colorTop); + +/** +@brief 3D plane with a gradient + +2x2 plane with vertex colors. Non-indexed @ref MeshPrimitive::TriangleStrip on +the XY plane with normals in positive Z direction. Vertex colors correspond to +the gradient defined by the endpoints @p a and @p b, linearly interpolated from +@p colorA to @p colorB. + +@image html primitives-gradient3d.png width=256px + +@see @ref gradient3DHorizontal(), @ref gradient3DVertical(), @ref gradient2D(), + @ref planeSolid() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData3D gradient3D(const Vector3& a, const Color4& colorA, const Vector3& b, const Color4& colorB); + +/** +@brief 3D plane with a horizontal gradient + +Equivalent to calling @ref gradient3D() like this: + +@snippet MagnumPrimitives.cpp gradient3DHorizontal + +@image html primitives-gradient3dhorizontal.png width=256px + +@see @ref gradient3DVertical(), @ref gradient2DHorizontal(), @ref planeSolid() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData3D gradient3DHorizontal(const Color4& colorLeft, const Color4& color); + +/** +@brief 3D plane with a vertical gradient + +Equivalent to calling @ref gradient3D() like this: + +@snippet MagnumPrimitives.cpp gradient3DVertical + +@image html primitives-gradient3dvertical.png width=256px + +@see @ref gradient3DHorizontal(), @ref gradient2DVertical(), @ref planeSolid() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData3D gradient3DVertical(const Color4& colorBottom, const Color4& colorTop); + +}} + +#endif diff --git a/src/Magnum/Primitives/Plane.h b/src/Magnum/Primitives/Plane.h index a2631037f..7f3ecb35c 100644 --- a/src/Magnum/Primitives/Plane.h +++ b/src/Magnum/Primitives/Plane.h @@ -58,7 +58,7 @@ normals in positive Z direction. @image html primitives-planesolid.png width=256px -@see @ref planeWireframe(), @ref squareSolid() +@see @ref planeWireframe(), @ref squareSolid(), @ref gradient3D() */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData3D planeSolid(PlaneTextureCoords textureCoords = PlaneTextureCoords::DontGenerate); diff --git a/src/Magnum/Primitives/Square.h b/src/Magnum/Primitives/Square.h index 4716f6cb4..b56dbf05a 100644 --- a/src/Magnum/Primitives/Square.h +++ b/src/Magnum/Primitives/Square.h @@ -57,7 +57,7 @@ enum class SquareTextureCoords: UnsignedByte { @image html primitives-squaresolid.png width=256px -@see @ref squareWireframe(), @ref planeSolid() +@see @ref squareWireframe(), @ref planeSolid(), @ref gradient2D() */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D squareSolid(SquareTextureCoords textureCoords = SquareTextureCoords::DontGenerate); diff --git a/src/Magnum/Primitives/Test/CMakeLists.txt b/src/Magnum/Primitives/Test/CMakeLists.txt index ef3493e77..ed4ac6cd6 100644 --- a/src/Magnum/Primitives/Test/CMakeLists.txt +++ b/src/Magnum/Primitives/Test/CMakeLists.txt @@ -30,6 +30,7 @@ corrade_add_test(PrimitivesCrosshairTest CrosshairTest.cpp LIBRARIES MagnumPrimi corrade_add_test(PrimitivesCubeTest CubeTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesConeTest ConeTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesCylinderTest CylinderTest.cpp LIBRARIES MagnumPrimitives) +corrade_add_test(PrimitivesGradientTest GradientTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesGridTest GridTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesIcosphereTest IcosphereTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesLineTest LineTest.cpp LIBRARIES MagnumPrimitives) @@ -45,6 +46,7 @@ set_target_properties( PrimitivesCubeTest PrimitivesConeTest PrimitivesCylinderTest + PrimitivesGradientTest PrimitivesGridTest PrimitivesIcosphereTest PrimitivesLineTest diff --git a/src/Magnum/Primitives/Test/GradientTest.cpp b/src/Magnum/Primitives/Test/GradientTest.cpp new file mode 100644 index 000000000..c0965a0fc --- /dev/null +++ b/src/Magnum/Primitives/Test/GradientTest.cpp @@ -0,0 +1,167 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Magnum/Mesh.h" +#include "Magnum/Math/Color.h" +#include "Magnum/Primitives/Gradient.h" +#include "Magnum/Trade/MeshData2D.h" +#include "Magnum/Trade/MeshData3D.h" +#include "Magnum/Primitives/Square.h" +#include "Magnum/Primitives/Plane.h" + +namespace Magnum { namespace Primitives { namespace Test { + +struct GradientTest: TestSuite::Tester { + explicit GradientTest(); + + void gradient2D(); + void gradient2DHorizontal(); + void gradient2DVertical(); + + void gradient3D(); + void gradient3DHorizontal(); + void gradient3DVertical(); +}; + +GradientTest::GradientTest() { + addTests({&GradientTest::gradient2D, + &GradientTest::gradient2DHorizontal, + &GradientTest::gradient2DVertical, + + &GradientTest::gradient3D, + &GradientTest::gradient3DHorizontal, + &GradientTest::gradient3DVertical}); +} + +using namespace Magnum::Math::Literals; + +void GradientTest::gradient2D() { + /* The corners sould have 0.2, 0.4, 0.6, 0.8 blends */ + Trade::MeshData2D gradient = Primitives::gradient2D( + {-1.0f, 2.0f}, {0.2f, 0.6f, 1.0f}, + {1.0f, -2.0f}, {0.4f, 1.0f, 0.0f}); + + /* Positions should be the same as for a square */ + Trade::MeshData2D square = Primitives::squareSolid(); + CORRADE_COMPARE(gradient.primitive(), square.primitive()); + CORRADE_COMPARE_AS(gradient.positions(0), square.positions(0), TestSuite::Compare::Container); + CORRADE_COMPARE_AS(gradient.positions(0), (std::vector{ + { 1.0f, -1.0f}, /* Bottom right */ + { 1.0f, 1.0f}, /* Top right */ + {-1.0f, -1.0f}, /* Bottom left */ + {-1.0f, 1.0f} /* Top left */ + }), TestSuite::Compare::Container); + + CORRADE_COMPARE(gradient.colorArrayCount(), 1); + CORRADE_COMPARE_AS(gradient.colors(0), (std::vector{ + {0.36f, 0.92f, 0.2f}, /* 80% */ + {0.28f, 0.76f, 0.6f}, /* 40% */ + {0.32f, 0.84f, 0.4f}, /* 60% */ + {0.24f, 0.68f, 0.8f} /* 20% */ + }), TestSuite::Compare::Container); +} + +void GradientTest::gradient2DHorizontal() { + Trade::MeshData2D gradient = Primitives::gradient2DHorizontal(0xfabcde_srgbf, 0xdeab09_srgbf); + + CORRADE_COMPARE(gradient.colorArrayCount(), 1); + CORRADE_COMPARE_AS(gradient.colors(0), (std::vector{ + 0xdeab09_srgbf, + 0xdeab09_srgbf, + 0xfabcde_srgbf, + 0xfabcde_srgbf + }), TestSuite::Compare::Container); +} + +void GradientTest::gradient2DVertical() { + Trade::MeshData2D gradient = Primitives::gradient2DVertical(0xfabcde_srgbf, 0xdeab09_srgbf); + + CORRADE_COMPARE(gradient.colorArrayCount(), 1); + CORRADE_COMPARE_AS(gradient.colors(0), (std::vector{ + 0xfabcde_srgbf, + 0xdeab09_srgbf, + 0xfabcde_srgbf, + 0xdeab09_srgbf + }), TestSuite::Compare::Container); +} + +void GradientTest::gradient3D() { + /* The corners sould have 0.2, 0.4, 0.6, 0.8 blends */ + Trade::MeshData3D gradient = Primitives::gradient3D( + {-1.0f, 2.0f, -1.5f}, {0.2f, 0.6f, 1.0f}, + {1.0f, -2.0f, -1.5f}, {0.4f, 1.0f, 0.0f}); + + /* Positions should be the same as for a plane */ + Trade::MeshData3D plane = Primitives::planeSolid(); + CORRADE_COMPARE(gradient.primitive(), plane.primitive()); + CORRADE_COMPARE_AS(gradient.positions(0), plane.positions(0), TestSuite::Compare::Container); + CORRADE_COMPARE_AS(gradient.positions(0), (std::vector{ + { 1.0f, -1.0f, 0.0f}, /* Bottom right */ + { 1.0f, 1.0f, 0.0f}, /* Top right */ + {-1.0f, -1.0f, 0.0f}, /* Bottom left */ + {-1.0f, 1.0f, 0.0f} /* Top left */ + }), TestSuite::Compare::Container); + + CORRADE_COMPARE(gradient.normalArrayCount(), 1); + + CORRADE_COMPARE(gradient.colorArrayCount(), 1); + CORRADE_COMPARE_AS(gradient.colors(0), (std::vector{ + {0.36f, 0.92f, 0.2f}, /* 80% */ + {0.28f, 0.76f, 0.6f}, /* 40% */ + {0.32f, 0.84f, 0.4f}, /* 60% */ + {0.24f, 0.68f, 0.8f} /* 20% */ + }), TestSuite::Compare::Container); +} + +void GradientTest::gradient3DHorizontal() { + Trade::MeshData3D gradient = Primitives::gradient3DHorizontal(0xfabcde_srgbf, 0xdeab09_srgbf); + + CORRADE_COMPARE(gradient.colorArrayCount(), 1); + CORRADE_COMPARE_AS(gradient.colors(0), (std::vector{ + 0xdeab09_srgbf, + 0xdeab09_srgbf, + 0xfabcde_srgbf, + 0xfabcde_srgbf + }), TestSuite::Compare::Container); +} + +void GradientTest::gradient3DVertical() { + Trade::MeshData3D gradient = Primitives::gradient3DVertical(0xfabcde_srgbf, 0xdeab09_srgbf); + + CORRADE_COMPARE(gradient.colorArrayCount(), 1); + CORRADE_COMPARE_AS(gradient.colors(0), (std::vector{ + 0xfabcde_srgbf, + 0xdeab09_srgbf, + 0xfabcde_srgbf, + 0xdeab09_srgbf + }), TestSuite::Compare::Container); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Primitives::Test::GradientTest)