From 77a9b7ac9d8b364358e1760e74a44e86557b79aa Mon Sep 17 00:00:00 2001 From: mpa Date: Mon, 26 Oct 2015 15:06:06 +0300 Subject: [PATCH] 0023124: EDF 11219 GEOM: Ray tracing in the OCC viewer --- .../gui/images/doc_dir_light_source.png | Bin 0 -> 10326 bytes doc/salome/gui/images/doc_env_texture.png | Bin 0 -> 4882 bytes .../gui/images/doc_pos_light_source.png | Bin 0 -> 9829 bytes doc/salome/gui/images/doc_ray_tracing.png | Bin 0 -> 7627 bytes doc/salome/gui/images/occviewer_toolbar.png | Bin 102858 -> 29483 bytes doc/salome/gui/input/occ_3d_viewer.doc | 71 +++ src/LightApp/LightApp_Application.cxx | 55 +++ src/LightApp/resources/LightApp.xml | 9 + src/LightApp/resources/LightApp_msg_en.ts | 32 ++ src/LightApp/resources/LightApp_msg_fr.ts | 32 ++ src/LightApp/resources/LightApp_msg_ja.ts | 32 ++ src/OCCViewer/CMakeLists.txt | 12 +- src/OCCViewer/OCCViewer_EnvTextureDlg.cxx | 237 ++++++++++ src/OCCViewer/OCCViewer_EnvTextureDlg.h | 64 +++ src/OCCViewer/OCCViewer_LightSourceDlg.cxx | 431 ++++++++++++++++++ src/OCCViewer/OCCViewer_LightSourceDlg.h | 93 ++++ src/OCCViewer/OCCViewer_RayTracingDlg.cxx | 188 ++++++++ src/OCCViewer/OCCViewer_RayTracingDlg.h | 65 +++ src/OCCViewer/OCCViewer_Utilities.cxx | 12 + src/OCCViewer/OCCViewer_Utilities.h | 8 + src/OCCViewer/OCCViewer_ViewFrame.cxx | 16 + src/OCCViewer/OCCViewer_ViewFrame.h | 1 + src/OCCViewer/OCCViewer_ViewModel.cxx | 34 +- src/OCCViewer/OCCViewer_ViewModel.h | 2 + src/OCCViewer/OCCViewer_ViewPort3d.cxx | 27 +- src/OCCViewer/OCCViewer_ViewPort3d.h | 1 + src/OCCViewer/OCCViewer_ViewWindow.cxx | 199 +++++++- src/OCCViewer/OCCViewer_ViewWindow.h | 5 +- src/OCCViewer/resources/OCCViewer_images.ts | 12 + src/OCCViewer/resources/OCCViewer_msg_en.ts | 133 ++++++ src/OCCViewer/resources/OCCViewer_msg_fr.ts | 133 ++++++ src/OCCViewer/resources/OCCViewer_msg_ja.ts | 133 ++++++ .../resources/occ_view_env_texture.png | Bin 0 -> 1050 bytes .../resources/occ_view_light_source.png | Bin 0 -> 890 bytes .../resources/occ_view_ray_tracing.png | Bin 0 -> 660 bytes 35 files changed, 2029 insertions(+), 8 deletions(-) create mode 100644 doc/salome/gui/images/doc_dir_light_source.png create mode 100644 doc/salome/gui/images/doc_env_texture.png create mode 100644 doc/salome/gui/images/doc_pos_light_source.png create mode 100644 doc/salome/gui/images/doc_ray_tracing.png create mode 100644 src/OCCViewer/OCCViewer_EnvTextureDlg.cxx create mode 100644 src/OCCViewer/OCCViewer_EnvTextureDlg.h create mode 100644 src/OCCViewer/OCCViewer_LightSourceDlg.cxx create mode 100644 src/OCCViewer/OCCViewer_LightSourceDlg.h create mode 100644 src/OCCViewer/OCCViewer_RayTracingDlg.cxx create mode 100644 src/OCCViewer/OCCViewer_RayTracingDlg.h create mode 100644 src/OCCViewer/resources/occ_view_env_texture.png create mode 100644 src/OCCViewer/resources/occ_view_light_source.png create mode 100644 src/OCCViewer/resources/occ_view_ray_tracing.png diff --git a/doc/salome/gui/images/doc_dir_light_source.png b/doc/salome/gui/images/doc_dir_light_source.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e08ceaf9a04ddf0c690aa161b1054c7cdac28b GIT binary patch literal 10326 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

Kt=de|&EP=9sO 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/images/doc_ray_tracing.png b/doc/salome/gui/images/doc_ray_tracing.png new file mode 100644 index 0000000000000000000000000000000000000000..49652579451dede3d966befee61d17eba03bb556 GIT binary patch literal 7627 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/images/occviewer_toolbar.png b/doc/salome/gui/images/occviewer_toolbar.png index c8eefa245bcc920a9ad472db4801c3da6b28be16..d4b293757cf7577d743962d21ed1ee810255250b 100644 GIT binary patch literal 29483 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 py}hk$eQoZc!S7Fv{AjE9rtW; z=4%SHjiPz%cjA5iR+ZXP7@hHH-wE%#h+z~n={y0JaPGLp6rM*JiRXUN@k>{-#mw$*ZX7ml`~N86^24Q2?>Bf3+K#<`)xtU1D8_^? z{!QxyU8WdKm?Z+M5ZqKT@uir^0VCt2!JjzmK=ve{7qAQ~M9)ZLfmVhvkU4#yK_MM% zT9lQ5hf+piy1KEC{tcWjpqR)oQ0c3~;a40$v<@Es+NcLaP||>cD80Opyc@m_DN(F~#}2@> zI8KTE0#ATaU(_gjJjF2gU%kL%S^t(3f7Zx|oLs~QP%6;=Q0$Pr`8`{vw9ToT3=~Wx zRn4Q^*n+{LC0nwbrP8+nBH_$WsS2h@l9cjn?8nnSF9vbn2L6}PRaxT%eejj39`C*!6LOPRZj zethBoZj5=5bod8pr15N_=f1KWVP0(yN-i{ z^Y(Hb7o(xmf3TVmh>@5CrH}ylh8c8~I=#VSThW=xPcH;B*p!-Z{~}5{?j2t|E~aIussLtCRD7`zP-M;z!c-F=p*7U< zxu7$tm#p<`D8*n@l&pjZ&Px2-u|I zy*JK7=DUCTcezd9#dYS?T@K?2r)X;5+xq>DZeK)-fe-%cw-@VvsUK3nJ`M{YVFl>g z1XejUPpezscr(%0rfzG`t{>sV{v5@*mBS&*f4z5D<7zxxDmh-tB z%q_T?t}JqWbCUp&6_2OjcgIY586XUg- zE)0Eo^6%hhrL`q!Y6&OZoi&z>PCO&!^ZLBu_ez`11wD1=*`0m!^^rX_Nzc5@J^l-+ zzO)*Q23n^RUyzGHpYdpDZ#l8Fo|c{TL~S9kMkFzDrw}IxYvg(INHUCu zrNkq7FfJ*(`m3JyaB@HVewN4Gl2w(#?IRVVcDYRKU9C<~A|CNju(FUF^mo~o6Txf# zuVAi5E=H}&R31lCGdmz{z>+d{>Wrep_AM9^ieY1IjTF|8l&4-ULVyZjfggap&zIMn zSjC95`~G?R3K}^ZYozXn=}7F!OoEsYfiDPjB1MUGH2JnQzSUWqQ07dus0^Qe?)>}g z@2xvK%4Q)X?lRZo4Zy+Md3%UU1h;nc8*h6maxBNgzinnW%|Kb58Lkh!(GB~*Ea1nRuCP!h&1Hp6R+S0VqhhsmRHJx;5|!(c!!U=HRmiGo+fs13MqcCBTc zu|l}m0|%fqHugHs`|{uCb=y6fY!9Cg#Sq~Gc6d~8sN0>+KJ$X12i0l1RUDSQT#C+M zR>@181?RC6r!SHJrr6De0S?*6Ck-o%j_wMLcseqk<;WDYJJqx{E6Hh~NAyIZ%Kh(AQ z>+VNIB*g%dm;yUHJ8h0YE07^9&V2548OuL9I+~c5R8SkOq2bP;D|VF$v5RY9 zZ+P+ZmyGz`YL3=lT3SiZ%%IuWp9lCc9!63oj#JyrD%)2uG{7F2(XjY)zw#g0zc?5i{mFCb0CyUL*-m?kl?g@ zn~r)B$ttU>&*ZUmRIv<|QpBQE=)cM9HSL&vV*9OFFv^iLP>K&&nl$h&pRh?EweA-YJ+Y!LTQ=%p zipy*8F|c*~{(3zxRnx`mJ+bPHO$$pU&-;frl|g~OnGeHh2$;b?lJIL78J*uhb14eE z!J`wH#SSMVW+rANWMpPW!TXFhM1Wxa`yoLiqaZ&fkG969ZQ|nM;;z)hGxXd(tStrX zuDcj!sb8i3rJ;B#xgr~cV$+w@ljMA}0YeJ3fgfDx|5AqG7 z<>l3VEfr}W__hswT6ZtJ1hb9i`(mDBFxU+X$6I^-=C~}+s6>(E;+c@xL6~rXu2C2& zHrDBP0tmZ1nN$_H1Ro3?@wV|$&OrM!oKMHqG}w{}7E2Dzj6Y2Yp307ApC-%-W~JvVHvDdn+SVx*iQdn7T<}42MlRuyEJEWKJ-4@X zJT(i=T`~i5;21)xD+JJZYFakfhBW6iFRUK>@uQq2B!b6w<99bcv2`I20k|fhZQa6oTcR`d4sw2Kc)17o8N1EggXX&2>iVyj&HexT z`ukQ8sn|^j~-o@R5^JlB^at G4*EaPEnJuY literal 102858 zcmeHQ2VfM%*WbHbdhZD&At8m{0;q)Edl7<4QHmnH2_h(6Y0{BuK@`?_8sv4A}4Qx z2qb!T=@>a%Ktz7Mf385SRwJMJGIPMp0W$~8958d>)p9_D;@@1E!bLjA)>R?mnPMw{doz37Z-hwS}dV^s-k@?ol0W$|) z9}c|P8WQ*@6q07nYP!te+Ke>|ByFCUW6T^dbD&B%KnkQc`mzvORA2qg;MK=lGqRZj zW)7IdftZ8eWtaN`m;~^KWFpOXYT^y{aS&Qmr?zAU*J{UabZgOi8gqo117;4qMjX&+ zOK-3|GMn$X8&fqJ9$$KEDYXc;Q$D4Bxu3RrW2pzmZ#52ms^ke&D%J4e!+-wyXA27p zG=QpV1Av`8d9sz2RbF0RVq)TxCr=(ddW2g`OUtS%qDmg03G(~zzZVr1jTu9_A)Bu^ zhy!oDg9E-jUF;q|Zv2+5TXd!JiPr46|dQ$Z#9XWDj&z?OA2?+rK0qEZc3>cuH7wFIR%2OdWX3UtecjCk* zty-NtdD6kb!PeH+WP!1G@nZUkluBhuNy*k8J(BseZQj{)xv z@DE5!P5EKxu6_IVjU79-UAuOiS@cB8MV8D|ONE@i)m3wvz}Nt!(YSHrwvQg2eed3_ z`t>bq)#t4Y zHuD*ai;E#asTe#<+qP|)si#hzfo_QNy-wC&- zf!~fUWI}0&Uj+Qc*&@<2B>?eLzfohco^%h&Ne2$>nkkA_4;g z@$uxKxl5&KX=x!LA#c6)mNuJo#pw4z(4VRclaA-iE^fDpCNLPVy*Lq12ifE8h4smm zE>7^Ri*qXx>Ae{@-_0m+78t&K0U;0y(aVRil1#W|Nf+(TefPmbfBf-BS?6A%QyDHw zBZt;8r4c81@7}#J6nzoB6Vk}9e#6O&m%u!yQmexnG;Gtg`|0CHyLRhVT2cZt7?!RZ zu5LL6BoHNi%OXUisOGGB1zXDV8uc&UBYHiQb@$2@X--bQtu3-+g!key2{-_6)~s1+ zY3bz~Hy)*>Worx)Lxv1Fd-klGo13v?f6nLn`|rO84(ySfoCBFeNu!3J9;7HAd_M?* zl#~>V=R7?cGrK&v@d{6M(o=c@98OM)20K&8#;7m zUK7F)9{u`lB!~n(c_Eql^jRMh(=9G8u666ydMH^*e83?*AYg0-gbCn$BvbX(oDW+> z80PAcPto`9FKA)wQ5yRP#_Wsl}eRd zuDEgI#_7|iyLRi!2Lv>n4i0;M+e2mFyLT@FLxz@(qj_S|WSro1D$jsG2mv6}hSHAV z3CJWf8GOa^6=Ja%qu|4bmuF>XxVpO9*w`?Ub%k}c7FN8Tj=rR%n9v9(Ru)|)Qt?dU zEnBwuH)zC?BH!)avv~Sc5*%y5Y3)rvC?oaI!9z(InG+X%0I@_0CzV>MRw-5Lj=lO^ zyKv!`Uw?s4PXZfr$r&0Fl}|rgOp~lim2&5+|D}KOWdS z)6>HuD?7{9&bD1!avV&_Bm~^rOv}Bz?%~6S^&8ZO$$`$LEAZ>iU&F#0oH-L4A5T1d zNGw?3CJ+c9wjqjQVy@WPxwLHAYWRo4Crqd?5)2wR=-{C;S*Qz^j&IVqiAEaH5gY-k z+oco09G?8)15QaJ)4+L3Bh$dEiY;Xw16>JLplkm@Sq zI(I>mQA4MwsHhJ<_yB_=nM|6LoSBp^t?h4PWkH07hGLZW@6~@Hs92TZyyet6K#7@v zGiT1=ch|06x@b57nUN-EWP+5-Blf)4s|Ek;v(NBZ9yzi?DlJwilM3>~?Q8I}dTaH` zBDsu!rHT=M=#ak7{nuZ99W{!bg~>7Qa5+A}lQXj>E#{USYuBuWt%g|{ZZxgfg9i_G z?A2ST={;10niNQ6<3#h6zTLh(#MP*g5J)d{@nDN7MJN?Yaj6(1#rU+e2bq~_u^6?? zNYBX4$raZWE1i`h#)O{{51?TPvcjuS~X}8sfyvf^F(gaqzULLyBt+9&R=L4mEyt1 z@}^rUzVZzVeD!Ll%IRfyY@uQdIAxdPgry>@q~^Ntd4ltDa0m_!vv+j#a(8odaIklD zf*x(};NarsZs+1QVZ<=126yk?1yA|QB+9Y@JF;4($S;!rep=luEVpkvyPVwOciwpi zR*vN4WPg8uU5`h{v-FG)hkr;VK^h@2V#EmiQeirat^kIatRxmVD;2jft3&I}h}Di~ z#+a0| zplz_SFth6qqjS_FId*T`GIHcd7|JS{&h#T{QXzUQM3xXjDm7`lL-oWZB~qzGA(P`4 z+9VGQ10;OdVgQ1XjGDp`Zq1rC2p}5zO7P5?bUGp_eXDFtX1os`5MZX;zI{6cJofHF zK^Vlm_uhL5W2OqfOO`Cb)E&rhK}69-^9*d;wr$3YDf@T(hSawF>I=6KAGK=v)-Z`g zg6wvWekiRwhQ`6HGZjzA=no_%C83W}tCdZf4CvNvFvb{|;@r72AuKF3HZ~3la6&=? zq!B5KjJ(+LKr6e!PG2iWMFg#6goY+?&L>qBIOj~5K|xzlQLPZO<}V0NYDfm>C!fYX zq3baGBeIJR-LO9J`SXYS4$<)#>;NYsB7%<5AAl+i0%R#EDRr__N@N8InKrq(g^rF+ zm^JOzts8XtPd@ns-GqJ|mY(t3Z@+;aUa;u$h7KKyTPjS0pk@F0=bslZT|yVrxKZQC z$U$(4p;K7_7C0*vw<>|#$w{i78})sSCTmCl_o}-)^HG_|*Df6~CWAZJJD|@6|0NPR z`m%!j0-021Z)aFZGT2&BD}$Xo9}w2_(pm80^hgeB3qBZ>jNSjRWy_WiqwYj>=?Y;c zMH%8!Nogrq1hd`ad-qzjXhBziRWbgzRmc{|fZ4NWqe_rB(2X!0g!*;w-aYii=)Rqt zoM88U_Usw_0#NANZ@-Pt6N5!Q{tiHfoWsy${P^+sSTF^GjvLIxEIniryue}IMHt0F zP+|TC1IP92*Q1N)?}Gr2Wn^S5`DWV9EB=idl5Pu&=DFi<{l?>e{2^$`kVdfAp)45O zP?k~rhXOQf)~t>l2SXGol?291kaTO-#D;~1UAPe2ub*>#dUX3I(^2>*eO%9pdm3H1D^!u zC;1B`YDk4I2N=FW!Pr4Weu+g$NT9Qe3pKLq(xnR|N7t?fCX;k2F_1$*rhaJ}ET{PO zmz{Q=o*#^xXk%v=b>qg;6)W1cX^n9o<54PtbjFIP${~D*D_8A0H+TG$X^S8FVV`!6 z%VZ^n0-rzk7{F(ZyvYHL3HNe|#7Z?-bIdNFXTiL&K#&UCy}O4yVhrYDm7?p`VCSwY zBcJ$&4IAo_9F%7xCghD3NS}WCX;5%**8%Uky1PqC#S)2FDv`h>Ra{hX;=sO}*RS)b zn|_+AVhdyjR@>~vf*TCiN=u2NBEj(C5FU7;&Liz2chcee;Bo&xMTR$vcM1_g`{wEAHl6y@Pd}|% zbyg}RBOsqpQwS$Y<1HzHtdiHM(;o5_!(Td!Iq*7gz<`6pnWLnJ8>_i6CW2ytQ5aO2 zxeFGuY7awPdU`s~sXXL`G{!G$-L8yRL%U566XPq(lfS%_#8aQLS0osauo5ksaST2E}T%6_g}=`MSHU zN+t7o#bA5w;1FFM{f+C__<&R@m9)v1jS7biAJ!_OwJz{pJ$fJ`Cf;d!7LKl4G&Vn9 z--Q#$kC-|=xK3S2Cb>+O_%v?UmQ7P8O{x`G%UD3|f~txw5OVjIEJ?q7IUyqhlm4ki zMJNl#SQub~LxL#{39dbfadFCmg6RDGbfxm=#*ORMs}~&;4dp|-V$2xWb@90;T3RY| zbE&*Lnlyp3c;n`cntnAwIXH6ggQZKU(%lInxu5`%52GK}ug}W|fi4T&_;OCdC*!wo zUhlPWYyRicU9GGHACGjt{I9xE<3>>5A!tc0Ex2}IP@t=ut5N*Nl3p*bdJx>`QlKhP z0ttN-z8452D8zPluBfw7m~_pJ3ZRJUE9L(mxJFyjt^ZNhFzN-s8U|^!X_H=OXx&h( zw}?SXDgOfOZYtaPW}!p2Pf@8AD0ClJx8GltTbHo#Q2 zxTwI_FJR!Xj}9C-ID7UNm2fpT%c-HmG~*fBwHaMG+_wNuJL>Hk3VPa`VEn- z+q7ZPpZV()D~8W4YyKH>2+{}_@}jwr=KRu9NT&Pu@9P&x`Yle(RM_r=!V^Op z;lq=NOXad$AAi5=XHGFG>H2d<(y0i*v)kUmlMvYab>?3?J1eXgi%d+McCx}-1|v17 zN2G?NwOyWe3=^3XJTWoSRX&y`dl7Jepl{WbBBH8C*Jt8{iJLa-9d^();0oyK+85bha3qu-FA{i4llQJ^sbQq{H6$GJ0$LI=RAc&`%_V_VPK;?yc zfh1Tj@Qcy|Dwl4o4+0Git7-p!JAAw?e%o6FfdtlKoP-sMr~@7c?-6=D9tvFnorO;T zHr~gN@7=w-vPX{{5=l{MX?|g0CIr&Mhfi9xXaX~BOw75KE&K9;GSj?F4rm-4bO|Mm zGk`!gx&=i-c{QxSluv9)uxvh~i(PuqX+s6t*k zckV3WnKA8DtAaCl@YWSn|yh_`6~zhR$p6U_W!_%&ptDf&gK<^hYs| z-~@q*VQU*}gW%d6YuKn^r_S$>9XA%sNbs#cej>w?`LH@+(A{xCIN>ee7lj%Hj&20f zs7;&I+1bw^jf#tNA&`oSAd}$lphRRw#^e42`WuC*U3t!!I(3rhc;HiibPUhH?w=NM zQLbjhe_}E?Jo>o6vBcbBE5Oz#yUPekVZpCjUu(T@=D_E%-;PtD=Q;kVj-3(z>t#*+S_{uYASf? z=11_-3?zDX=@@C;a~Wij+QwEOF~Z#(^MAfRzQw`C@G*l{gzpGnB3xtkMMfrFy!c;Q z+WYzWg#~bAb;N)S8a#S=j66buLy(JpSY2GV6j?etI6~M!S)}vAo_6rS!6VbBH|f?L zyUD?rh8U{!tjsJ>)~s0*xeS7{3PsJQOqsH5*)oh%t*w=qPdfjP7z^+{+&xg|O2p;w zs8S@?4Rkw1V^b)2-<>+Os!5Z+#l_i0Mfl4qF3!Qw8pfEoxJxTnersiEWo(7H3S`Go z{?PEQ?$xUox<|OV8dVB9cTSILs+iXtoYRXPHOF!*DhVF#2G|n$_5QgAR3@12*i6S( zn5$Q5M|ydCVN(qLLlBXrh%$X+015>i)9o-qz;1^~Tu_$CC3y-3J~#cC`V|jm>XXM$ z9BpjY&--e?$k8Q(+&OduJ3D4*PiYM<0E} z%!P1XK_UK%Wg<*LQb|fVIemjLlT!ba@MH_>FXkjl95@pGQ`ULa!ojZ46bJmZ^9!@c9 zMo#*a4Ysaaxw3KndPfTjwTpA~m5UdS<~X^yloS>W?%Nkj16ea%GzOiWj$s9`^Gs1; zTAPUGmNp^Di7C@Qn-N&cukp-l#E~*-1bST{y5i{~IKl6ns(qzmX_(RA*c=NC|NZyH zIXTw$_D>EUPC`!tfuxZ}WhLWj{Iv(Hwstuw$rYXZXtHzH|JDdw zJ3?GaKdJrzB*(5_f2AY`q!C8{UY=g?JistQvp5o4E|9A>NlOo05Nu&7oTRX+Clbf# zhjoH3U~7xv^GBb4iZ;Nmu$qv_RZ9EC!;g~j~Yvzs<;in4SGAtsc5a8SaA7akrqYt|>FV#S0> z%g+COb;O4QnFw?pSdn_-Y0ByVM?a#G`UL_(%H_*qbXa(U80|tV(d8ll4GA+82#^|* zrh{XqYKJkxt<=Bt2_b*=>eXV+ZkALc24!gC)UXRN2tzG}a!Rq@SS{Gw#~Y(* ztROh8tpeCAPDTz0)LcJap|DQ zLD~dNWGaj-xcE?ltY@#D*f0LUg9n%^fl7o`E4a|`pb}|dD*Y&J>syGUp(o+DQi9eE zdDj^09vuA^L6}lG>9tBAFprK%{cJ%h#1TcNji4t6 zb}bm|EJPNN8K}?idw;L@{s;3yLUyI4;jky9V!{;h2*4|X!r@tMiul`azeNDgi%H(+ z&!5L6CEZO=hyM{Gan1%tHkc8HG=iuz%EE@-Xm8!R)x3Fg;9wT1sJQ6n@tc#zIZys9 z^OG_2-+KEkqbf;N)!;9dRN?R9rHd~DzHk3N^i%P-uuMEo&&k44URRn%;HX;y|Cij<>yYHMC8InE9cEyF>l`Fo_%_Fx;oQj z1%>2NLgw{Kz^Mwr;(zA!8Q4N`3-t)oFt{**#H^m4FltWOh?q12#%@IF(u(FZ{CV>7 z3SR(b4l>Nl1^qx9mYqR!kLe<8tqGME!xt!7!`>Jh`D=5LAE6D!~;A+p1v0?!kixlg76?buea!9Rf2+d<+BHuv84dF){$p znFQGV4x1!nh=7mLSa9?(XppEXRy2T<7(`Eo4c-)TOpEi++V+)Eqt~dOA<4 zZl-mQW^jso`Wze}?IH6)hnY;g2?QXAB3eZtk|mA!4+^MKtMHdK{mw$Za`}oB2Znig zjF~c}HSZ1iXb^4iAAb0O>e(rpTeoi12??qbG6A=tbwh({`(|ZkmP#<2O3HHm*GmSc zDubCAXrh>R!Bhu2L0yY(_0(MZU8_rrD|XAXBT5+ZiG@>%lDD=5g}}FlFRBf^17>n=_QDBb?6a7`DK-k2ra4Z|zRr;~d~2jxkBej~qUB8H1 z=dnOA6^vn~HaHwsF<@j7Q@5B5_VukHva-YGT-KKQ4EL`DoUSuQ;;^k#<8jC&80ZX6 z+R=GY^B3tlX&iIF%mFh8%pB0>fPl|fUOU@s5`*CtTwSZ9GMI3JKr(}~cnh`|G+D5+ zm~YJ-Fmu4n0iGPt=itB-;?4-0P*9u9Vc2YC<-{nmJ(RfSCi;$ALHA zd{=#}scz&$hZ$P~Rb647J9Wki$Ew3KBbhm1=75<4FNp(hyo19_;!`ygQ+?hOW*>xV zcwMgrFbNWzWpU=#B4GXh>I^Qx|J?FF+{hHdsi zs4`Z*mOwB0{l4VlUQ3pnEA?_XKx#|mi8JQwrE|dGAxba3M&<&|958dh%z;IR*m9!PJB>DO+R?pxcmBByQep$Q=c&&rG92EqbLY;XLx*CITI_Ix z9WMIx>GSTp@6x-M8bs4Y;Oyj5P^dZELKlUR@to$_g$r)ftJj4;QcTR*g^OD9q30}) zPe#*duw@Z5BQ`N&-d0mMzjGItb7!jp9OHZJM5V-r&jNuQyWlQdxCz@(VV_3K@?tAO zTxZVwrc&eJOiQ)ef>2}gUot~g6m2?&{>G!-RK)%PRAIKsoV)UyUK7LSJM6A#5I!a* z20OoD2R#0p(@>bz3Qku$Tlw^Ig4ci$M>?iD0!QKs+Xm&hTLke0f321ctyr-F+lgXV zZ=5~Lv;HrWEbVz(&6@VV{4(qIt=l+kV)syoa@xJGZkO(f}N}m8(L0|;of0R z$Ti~OL*o1Ir@#Lz&$E2^l4+jp*s){SlX*#W5ak>q*1q-8JXB%+SndUs|YnAfJ{;e2nD3kym=d_gD28TN>yrgP0b0DI1%RI z!+)@mI^+gl!HU7@O$>` z+0I=$2LP6A&#zG?%7s^?P=JG>R(xuj=Ss8gl$ zhjbP6I%r61Rdw$a1z5Zi#_)B~P}gD^`u{nzQAw*Qo#UV7?uzvj(0IyyN{oH!8#*jg07=%G@d zr<%}@Y*@bmN9o`&4m>`X@a);MzyA6QIuj1@LM5?dDI_$ugvT!0&MwY4Mu=G@o?+DR z>ZPl#+C&^Wd{81u$M3**2O;md^XF_tHWBS2c;c|gbg3-v?q%av7CrO!`@8_6#$aOM zLL%m@E*vI3!aT{Cxv(AAi)c0~wOpx||M6o2^i=2;Ski#u0@@__dE&$gzZOX#xUZJW zRMI;e>UVH&GG=KroZ)0bJ*heubm@wK)zG2oKYVXg55|0CO<1j2A*mt+3LGanW5)6= zTeg%)BT89rec$nh$GkVtHlJ} z5$;=uen}9#eE~Gu5~MZP1>tc!x^VYTTxsQTkW790tdEK579St~PRTpv(T4v8c)xxd z2}0ih2jHlHt$;8VoGLz7nYb^?W63#Du~hDCBP0d8jwdx-T|*S;-9U2YiTvM0t1mm3 zyw@blT@k-Q1WlWAq~%OkKNXE!87?w4OvA z2ZYW5qf`8OcA5YA%+FV@T4}O;I(Xn<^A^p=jvYHVaxjj045$_Gyu7?{x+8VQF&K;8brFMZ4jm#CCLC$__xZmeR&g!{c2+c2yQO4jMB4~7jX?uR znY8=2-6xL!*{g4FNwGvCk{D4}exz&H;&ffUSC1aw@g>zuw{gL!p;K3b`MMg+Z=ZkM zW6nxF1lsUQwM?m!bsgn_z}mIqfByLgYHPc;?J_p(`Bx^Bt4i*uq>x@w>l+spi9gxe zbj9e)W7jmqAsyH-UK`C|jKz_|$^q~G)U#)!*f<=}MIR1lFe4WM^dG27Dwyx6ogwk@ z;!5n4=Vv=PdE+E)LXFLujp&$`FZ+h8T#mTebLMiy>WI?Qc&Mf# z38+P7g+QWY5`GbBoP5$zdPQ{P*Zb#cyc{%k(296X2qz^$BCsM^x0Fb#h(yOs_RWSb zfNMmOK1xa?RZ#E-r?TA1&YN}2^=3-hw=b5e7M*sg;Z)KtSRUk_?_m*Gf&2oYEJb`m zuIr_zmd^{F#ZnoeQWuMrU;ZIK6y>&}Z*I7!n;vXVF9(PowBgXs<1mU>C<(GDYnY0E zAwD2GVAfc^e9Fw3Gxbe&=y(foC#E*0@Mt{|0tnxTRP(h^f=QuLC;vGQ;serf%H$~< zHf+$<&**t5Bn=-v9CJV`zg>y49333VCZQ&9nl|jUk76G2Y#~$;!1;OmrpK|v+}z4k zxS$}XUcGBUiNc}h#YN;{AP`Bw#7Nh!{0wpZ)uU4(`oV1+UWg+*VCqMQ1~G(FPbpOv zN9CdZFizuOAS`kA^zgK>v7qzv2~Y>I9z1jqhaPU+fB_gWZ0Ilurr-AL7E8o@jv&`r zijMb7(W4LHIlHuPFM;`j1q)i}EQm_bTb!kpDlRszrsk@IQ=ZGxS;0+EiMrB_f)qOV zll`_l7FyH2yZ0tdB<(WZQ`kcq94pwY$jH85GzoCFQ=OBMuOQ zxH3X2p@z$s!wXs8_3yv`96kDnQQsO3*K5%)Cl-vLZ_5JZZ__3*kqOJXW#=;fp4-a- zrWZh!AM(3e7c3McW|C$YP+oCnLgg?84tY~KntjI-hdjY4ln1$a{kAHKrBWJHCMULE zmQlCuLR?n#&#j}e0MP^{1Rmw*esR?8QXFJnML`tK%>;S>ZNifiavHellu4Xw68gd5 z&J&}Ktq$!zU8Ybe%TMV+Yeu_8yOt@`jfbrL>Z_5{+qNA!a^$vc+u-qlTNt7sn{g;3`b7Rm%d(yY8W$BqX-z|i41*;P zF<`6-6{esJX4IY_VAYB_Utkc8lVJPS;RHF4FR&B|AO5vP-F=*!yBo8$P`M7R7-8k4 z%(%ZMBUW|WTG_1CdPpu-WwdWGqonzhN6z$Hy_!6}7&OVV*FT&1JmzF@Zuk2VRq4&S zZNw7Axr1YR`_wBa%>hAdTr6i*weguTuoqw!?4UppyKEUVe)jCyxW!2|FcRaOIDWQg ze0Pv7q=*CU_gPTZq>oKYr(EQA6#dyA|h(hPPnM%p{c;=ou{Q%`q} z%JGYe%F2n{Cdn;PQskbFB81V)Q@3H>R-1+h8@RgZVF;&&1k0R6t_tWh_3ExK>ke2< z0YVhvLYqJUEgUkb`RMHvCJfrTZ7a7-;(81C@Sgv@+N0fPkU;p{mC70yX= z5qG2RjvYsew|R4~9Xt?s{dy>*5galoOiCr91QHqMdTMPF8ZvbE&)fSA ziro3*55~fSGg2F^9N+gS6Q@|I5F&#OqLj%IM&k03Wi8Iir zZy(s}4jeduv%;G;YYO)leDg4RbnVs^elSJ>LS{qAqm->%9{Bj!tyq5h{)1iG2xQ&M zS?%uTo|8+CmknMcMvPdqW(|&ghcyOOg)IdRJva-#Lx&D;zy0>orAu+5Hwb`3;nPJJ zL}n7eOb4soPe0^+^64kLf89Ow!(l)D@FPKpt5rkNGbzBV8^W;f8GJ5I0(*r8p~Ret zkRT`MG1vQdN@xg_BpM&N{@MB=6jz~*T3`c#L=cv$M{&uVXml<*fKl@MvudHyepf!< zrIJV$Dhb(oNz=8GY^$2%e}vZ&)W|f#7ofa0DJh9m(9f?H0^n153i+>5oMC2!e6q12pPiOZOem{o3Cvq& zM$YikWlO)D^CizL`n()C(chp*cag{P4{|!zasB+4OhPIr1P;N@ZmWkstL^Hr;m@q+ z&&3C?+Kz2!$^#v|qI&+k5Yr1&dV5alEp-uimk81=q!KqFv1Wv4kLK2vawmhhoZ1q; zMj7UB6>7}%z_L_pK!xp;9F+S@=3dNd?)0`Es>P^ z^;SRzmCGasCE5)6M_Tj{F!I{FXLnlS?ML@w148Nz95}FjhxUPif#~;P90L+2X2hkX z3+BuS@^`A!tQ()T0LT>@f;paR2;}BU{`m7e#;w{`6v`csSy{*@xXu}LdZ<^w9)vv@ zf`^4}1bSHcar!nyGN#p^KY#w;fB*ID+4J1Fa{vb=vk0DHh)Gn2a&bVGVIK{HtAni# z72w9;DOtHQbH&nq3Rj}(aqbdK&to5{xA#{8o@(N zTO@v47Ec30Q-ZccniFJVg;*(H~^vRP6u}@mJYoD5&BrGOtt5ON9t?fi2 zu*L|suxbJPpr8;sk`ha}y?XU;I+A~&`KY*ElVC1X#>dBF+5`P*r5s%OA&+EoHTqwv#>S2DQ+X#_ z>3blHM;a}VxS%SPg^|Bl{NTa;$59uQO8L9P$3)%u@8*>Y&^d|TZ!-yAi|H1Kn zyP8Ktl$2zjI=ERTl|)3efsVq0V%>J?)M@qVeP7HD4+wCyx3ecrD2)2RPx!)x3)ik) zg9Q(=iptx*efv$DHo@xw8V?JNbqk*b_^5B*ycr!6*4NdqUmsq9m^lDfpFDX2fdqvH zc1Q^O{JeabRAyt10l(4LpU3{pFU}Vii=i#S%^@#8Z_<=W=T4JCj`Je5J%b-Gg9)4< zbfm870h)je7)0YD@Q_-TO`X64np|ol@Qk~Z8dA|Yrv5m}%T^%78@3b>7D7U(LBS6f zTBZ7sH)U;d@XT79HkBo!f0vX(-;i4E2o=cXEkcvg@U9a?n((~LqWqKN1zrZIkdp$* z@I}>`7qVda@@08NyMEd44q-W9a9@m{ATwgJbJ3_^qbMmZwpS{qeDTGRBU@D}D|dG< zTN`_LK9B}blP*f8>deZk&K0>KjWV9a()YAvLJVt$k~tr#>xJU;q@Z%LNr8lht-&!M zoT|)xhr*}mA z*3!wpiFXZuzmNiNzuGdn43oo7&ZMU3?%^&|D#99vx9QaV?wuR5lH#jpe$URz8W=g4 z1;x6JXdN+cp69JwS*_dnLSGpaIfx?ga3_tfNy$m~@83raGcq$!7UjM>fBt+b@~yYu zVxei@y12T)`4e7MuvKDi2`ew*hmT1wIDTWvEYu^&d-!NTy@MYz7Ds6#7>t2bvr&+e z48C>*qXVQ@&@xxkA`D7{JU2){*NQnkKu59y2GKYPFi%9zLzAKims%(!wyM3~Vi-D|Y}RgQR>DQN=fDK5i;RlLXm8WzH4l>`?P4l zAp5B34=`ASOgd{px@!V$%9JT5PyJ9_tZ;O2a&&SD2&fgG@XX%cK|ivt)X>nnR8n;G zeJW7Dej}QgC#z|CrUarRsQ_z+k~tr#tCZ}VY<#Ei7{UMxU)j~GR}rI&m@ZD^;9!zD zf`)h_0+2?GdJ3!wg-9w@%T0T70UW(WDz!DC6bUd+ECY5?2QZ2-9ON|F;R}Sxj zJ_t%uNK~$4xlAIB=@3W|C&1x^V%1>!XVbr3F$-Cgaw$ZeMiQZ$5Fj%pnMjF5uHGwu z9#($cx6x5Iul;w|-Z#iTFX8%=WDf_M{ylr#y%QA_TpLC(bo9A5t1|C95JUEC{ekpu!ekki(K5oCxa#>~8ev|r1Pj``fgH~eXhb$b z8_Z^BXK7qo2m&ThffaoJ2?AX)sQ?K0o4qu3!+cVpR3@c0q&4XmZ@3{9;+NNBlBXqSC)mP1g*i z{#=wyqNP!#@^sv2G^ENyV{J6C4&p50afZ5W9Nw4}pPro#U+_*{$!K`rL0h83`}glRSdc*i zR&kW!jx|k9(-=hKBq)V^!3H{LHE5s~>dkr1jT`x4Juxkiz`E4%rFJo&Q^q>jrQ}N3 z_5fBcPv{zO1<1BZ2%#h)k!*_u0e?th5tH=f4Zx z`Nril_<~=g3z~iB;%}H$!VqWnq-M)E9-TjZa9~j2s8I%<0z;XgU}DR9`Mh~6+q8ZA z#`P<{HC$|LZUPtItN?7&eAFTfYcDS!FE8)2XD)@-5n$!pxwGf`_UlU*&nIx}7CFy~ zt9f(MObvxhb64qye!xnxTsL3MZORo*#x40K>eQ*pR4V7-Mt><;*;%lY<5xc!UAh5n zNtZ7;m7ntDhF^HMZr!LgA~Y_afG%HfW?rn3>ej7+vEX8h-0wH0?mwE)`fZ=D=8BzE z6{-@1*113OGgEURmOHfcw-MPhjVjEdb%hGgW%-T*14&+!YmrV4_f% zvU=_FE7#Ho_YWHLaSc0lnNd|6jZ?*e513e7sv@Ue$pu3)NipPyrX8a_lNXF{m`RdL zOEIN{cT6SY#(g@J3)kxVZ*}goLoTgxjZ>Ttzcg3gjw*Tv67B4VFVS zcnGKAb3-?5AjuajTmXEm8^gt!9nuH{oJsm4Noh1!<4w+>gERslTwzi7Pd;c}S`vpa zBb_^lAyG*&5p_#B@za*IYC)X&3x(1fHxJ{}qjv#3dGZH*Zg#e4u-4JhG4-1WA4jX8 zRd6Hfj%BGwlvvVDZbXWrb}&UPihs(?#%pepnV~!kX;dCG{IAABs-yGKFO4W{NF#rL zf0$4(ZuRo?(hO@1mkJ7=(#SM$xw<4ZsYqN{diG4btw=p}nytuIhOQQR(!QV5xBe6@ zR46SiE#4pOBNQ8L$yJqDy&vgw=qxs;(mAju`ga>yh}DSA(hFk)*< zoNod1^H_O9qNvGznqW$Lo^%R#`1s}i-8Ef+W+;pKR>&*L#Rv^UN82c?jpm=$5pBFL z+)Kx>8KMHS43Lf@p`v!}W-Y=;zc={LojdE^PrzavYa3?^D;wZrJbV}v(X=U;iCtJR*@KqWqIrw=`t%uDx9GaRq_E* z6S#G$yZ%nh#5?~shjd35j}1r-Kb@vvH2cHrQ!u@XT>+!Y>9QR4diYiekh@HeGVi zrn%6bv7U@4c-f9K#R1ECpVy@XbL3fI$-Q5GQy#gW%XJZP{`aW~s=X&0*fu z{Dn8`hrK-3ty_l;9l(U1J;w|g(tq5zajvdDKmYtwbc*$YSt>a17z8h?S@}PlDp7f2 z`M+E*t~|}azoMs4Syf`rO;#G&yg(`1l^|Wf)#&lGE~BIo>_QD1Hn6p`rF3U4Fm{Ad z(#TkF6y~V(n?Bv@;luRwjN;>eJU;bTT!VVm%;&7s#20>K75nFVL|CC)Y`^6sCE!iQA%!JE*8V$ z7hiIkMlxYAD683-vI-&$GU`w3>Ddt=i|}!~hm{tjxm?3fXk0R>BgTQ4#)Wr-Rk9uQ zI4f(R2y+ZVrL{=t8(?Q|#BL6#IhIFmZr}dv(WBFCZF}|Zh4JU-3l?D3^uW`nt$ch? zr!`SgnW3Sdu2}=`b5x04OTG6NA`4U%f1tvn!!H91zpyw7WBllt=zaV4!L<)k{QC9l z+rHlhiO6EOUTluUyzIP9-)+2b>4GNhNM3eDn5=-I%5xHY`4wr{#I=o>HCJvqvi145pe!G{%4V+%HePBn78JIYF z!uWQkjwzTof8LeLR}vBuK#7-*jjs?uW56U3BoMZng5Hew0J{SAaWGi(ntnBp9lZrF zI}c9}q{jHvY)qp~Cn$_1tenR#txw`|w!bKA(O(-oo2Q5c^m?a(J*o zaOSi8`|m#*b2}NQ$J^T|OeVg?(>O(NFn*blR9OFVC2e|RV>B+{7~5)H)b{FH(Ul@7 z^#uY08j`^!Ak3WA3QiT|@I=thu6gChNvC1m?E;gU<# zAAArB)n(0^8<0Txd9o{43Td4Bbv?gc_Li@cHyy(npiNKARE)?lbQ>XEQok$fO#+H7LoH zl6K7U4P9&a##r2JL0BpUDv^~) zU}K%AD$Vu@;th*|XQ~u3bZ%oe$r>^W^V;utDudHEX^b5dpH)l9Ii# zvA2#Lg^`WUWm*7_bK=hv*xVJK>-a?0A>hPnxK) z%tJCU!=#2(6&JTMR29e+1{xC72!sdPu7tZhsUC4{C6CB~jlZJ^D0)6skgH0e`IMH( z#3fSL%5t&_x_#_YSO|T!pt!iO$ER+vY?H=qNpY|7?ge>8u(D>Q8R3C4A~F#l)YA1< zw{MfSG7N6uPD$_4U}JLg;X_X3gr{<*n3r`{&C5-mMKZDx#a>owh z&Yjue;h#5aMiV3y7JhL0^n@8RFt9ZWlSZHeTeob*Cg4~n3pERK^`}mqLRW=zDxlzj zE#MWFK-CVe{eq>SIEID%kI4XkjV9S7KLtNbT zkPvcZ!u5Yu?K+XOwu`?N;g71&(gljybG||m{J}q)F^kG;@RvU(1tr9Wfeg98yk#lh z%%Kl6i@_=xB;a;%fYj;KsT1Co{`?q4g3>5G34qlK&Z@Ar+_igq*Y;guSWpQCmU5NE zP2?vNs}zQ3D_KY!x4`jp_4(vOpCVDJrO+BS2TKcEONld9v-7!hc_qNE1(z`NhI8l5 zO?;LpkuuyTv~Vf!23=5E+o)TuhIu1!5WqH}YvXJ*cx`<3=q4myE!C*Y)6Xh_&_9aBnh_Jbt{g8;1jEyby9 zsPo22!w^3e#6iBBq9fRA!QCVdlh=X$bstp%vlMLvN5kJ8xEcL4Hng zVS%``Sc28zXx?zaA$`{HGBndjbQUbPlS{E735;dBXKra~O)CQy$(vEsf|@-T}C43a|&bKwy35?16c6mu6?(Uo=P2=Urj* zx5%=vaoF1B3M=A6tXSfWS&f7cKdO*W{BoATlt7#WRTZfb)LJ?NwzCYZ709;?t?c?U zRx3DX(KgaD&upB`hW$Y}Xcm@RqfdB^?z+|BZnLOIp){YHj zO(=B8KA zUid34EPVR(Db^MB2@4Ak4<|Q+Fcpwl1f1*e;NUsHF@=Eb?=XJCNSUGmf6~&@-~sW1 zWl`HjGs~?A^LYxrG;`*#z0WJaIYWBU$Q%X<7_iveuAFv7rV4e$@Z7X+!JQ}FNrftF!OI7#l`^k(MQ;cFSS6NjMCyb3nHSkNyB!nwp2F5ogvZ!(y<#z&XlBOAUlt-BV zeJLCW3k}1j1Nw_X_lKSlzk0|p{Df_RIYfmFtCCT+ob`f#Akl==Ep=zpgsY_&$~$)P8azMgJ{}H5PBvpkdHdY;!&{2h1EWbD$bIAXslTMQXO;RU?P>Lz@Q!`uSr{HFLns ef&VoQSPiW8_x9$2SiV3IJ-hbna;VeD#s3FXD0T4w diff --git a/doc/salome/gui/input/occ_3d_viewer.doc b/doc/salome/gui/input/occ_3d_viewer.doc index 09e821b48..7f79605ac 100644 --- a/doc/salome/gui/input/occ_3d_viewer.doc +++ b/doc/salome/gui/input/occ_3d_viewer.doc @@ -295,5 +295,76 @@ or other view operation done in one view is automatically applied to the other view.


+\image html occ_view_ray_tracing.png +\anchor ray_tracing + +Ray tracing - allows to switch between rendering methods in run-time +in the current OCCT 3D view. It can be used to produce images with photorealistic quality. + +\image html doc_ray_tracing.png + +- Ray tracing - specifies rendering mode: OpenGL rasterization (by default) or GPU ray-tracing. + + - Depth - defines maximum ray-tracing depth. + + - Specular reflections - enables/disables specular reflections. + + - Adaptive anti-aliasing - enables/disables adaptive anti-aliasing. + + - Shadows rendering - enables/disables shadows rendering. + + - Transparent shadow - enables/disables light propagation through transparent media. + +
+ +\image html occ_view_env_texture.png + +\anchor env_texture + +Environment texture - allows to set parameters for environment texture. +This is a special mode of texture mapping when specular reflection of environment texture +is simulated by OpenGL using a special texture coordinates generation algorithm (a sphere map). + +\image html doc_env_texture.png + +- Environment texture - enables/disables environment texture in the current OCCT 3D view. + +User can select one of 7 predefined environment texture from the list or define its texture from file by +choosing item "Custom..." in a combo box. + +\note Note that the environment texture file should normally satisfy the following requirements +in order to produce good visual result: +- The image file should have 2:1 width-to-height ratio. +- It should constitute a 360-degrees panoramic image created using a fish-eye lens. + +
+ +\image html occ_view_light_source.png + +\anchor light_source + +Light source - allows to set parameters for light source. + +It's possible to choose a type of light source between directional and positional light. + +\image html doc_dir_light_source.png + +Directional light - creates a directional light source in the viewer. +It is defined by direction coordinates, color and headlight parameter. + +\image html doc_pos_light_source.png + +Positional light - creates an isolated light source X,Y,Z in the viewer. +It is also defined by the color and headlight parameter. + +Click: + +- Apply and Close to apply defined light source to the OCC 3D Viewer. + +- Default to restore default values of light source. + +- Close to return parameters of light source on initial values. + +
*/ diff --git a/src/LightApp/LightApp_Application.cxx b/src/LightApp/LightApp_Application.cxx index f50576ea8..3093f12fc 100644 --- a/src/LightApp/LightApp_Application.cxx +++ b/src/LightApp/LightApp_Application.cxx @@ -2515,6 +2515,61 @@ void LightApp_Application::createPreferences( LightApp_Preferences* pref ) pref->setItemProperty( "step", 0.1, scaleFactor ); // ... "Clipping" group <> + // ... "Ray tracing" group <> + int occRayTracingGroup = pref->addPreference( tr( "PREF_GROUP_RAY_TRACING" ), occGroup ); + int rtPref = pref->addPreference( "", occRayTracingGroup, LightApp_Preferences::Frame ); + pref->setItemProperty( "columns", 2, rtPref ); + // .... -> depth + int rt_depth = pref->addPreference( tr( "PREF_RAY_TRACING_DEPTH" ), rtPref, + LightApp_Preferences::IntSpin, "OCCViewer", "rt_depth" ); + pref->setItemProperty( "min", 1, rt_depth ); + pref->setItemProperty( "max", 10, rt_depth ); + pref->setItemProperty( "step", 1, rt_depth ); + pref->addPreference( "", rtPref, LightApp_Preferences::Frame ); + // .... -> specular reflections + pref->addPreference( tr( "PREF_RAY_TRACING_REFLECTION" ), rtPref, + LightApp_Preferences::Bool, "OCCViewer", "rt_reflection" ); + // .... -> adaptive anti-aliasing + pref->addPreference( tr( "PREF_RAY_TRACING_ANTIALIASING" ), rtPref, + LightApp_Preferences::Bool, "OCCViewer", "rt_antialiasing" ); + // .... -> shadows rendering + pref->addPreference( tr( "PREF_RAY_TRACING_SHADOW" ), rtPref, + LightApp_Preferences::Bool, "OCCViewer", "rt_shadow" ); + // .... -> transparent shadow + pref->addPreference( tr( "PREF_RAY_TRACING_TRANS_SHADOW" ), rtPref, + LightApp_Preferences::Bool, "OCCViewer", "rt_trans_shadow" ); + // ... "Ray tracing" group <> + + // ... "Light source" group <> + int occLightGroup = pref->addPreference( tr( "PREF_GROUP_LIGHT" ), occGroup ); + // .... -> light color + pref->addPreference( tr( "PREF_LIGHT_COLOR" ), occLightGroup, + LightApp_Preferences::Color, "OCCViewer", "light_color" ); + int directionPref = pref->addPreference( "", occLightGroup, LightApp_Preferences::Frame ); + pref->setItemProperty( "columns", 3, directionPref ); + // .... -> light direction (dx component) + int light_dx = pref->addPreference( tr( "Dx" ), directionPref, + LightApp_Preferences::DblSpin, "OCCViewer", "light_dx" ); + pref->setItemProperty( "precision", 2, light_dx ); + pref->setItemProperty( "min", -1.0E03, light_dx ); + pref->setItemProperty( "max", 1.0E03, light_dx ); + pref->setItemProperty( "step", 0.1, light_dx ); + // .... -> light direction (dy component) + int light_dy = pref->addPreference( tr( "Dy" ), directionPref, + LightApp_Preferences::DblSpin, "OCCViewer", "light_dy" ); + pref->setItemProperty( "precision", 2, light_dy ); + pref->setItemProperty( "min", -1.0E03, light_dy ); + pref->setItemProperty( "max", 1.0E03, light_dy ); + pref->setItemProperty( "step", 0.1, light_dy ); + // .... -> light direction (dz component) + int light_dz = pref->addPreference( tr( "Dz" ), directionPref, + LightApp_Preferences::DblSpin, "OCCViewer", "light_dz" ); + pref->setItemProperty( "precision", 2, light_dz ); + pref->setItemProperty( "min", -1.0E03, light_dz ); + pref->setItemProperty( "max", 1.0E03, light_dz ); + pref->setItemProperty( "step", 0.1, light_dz ); + // ... "Light source" group <> + // ... -> empty frame (for layout) <> int occGen = pref->addPreference( "", occGroup, LightApp_Preferences::Frame ); pref->setItemProperty( "margin", 0, occGen ); diff --git a/src/LightApp/resources/LightApp.xml b/src/LightApp/resources/LightApp.xml index e8a0858e1..befb3b4e2 100644 --- a/src/LightApp/resources/LightApp.xml +++ b/src/LightApp/resources/LightApp.xml @@ -160,6 +160,15 @@ + + + + + + + + + diff --git a/src/LightApp/resources/LightApp_msg_en.ts b/src/LightApp/resources/LightApp_msg_en.ts index 987657246..8fca4a604 100644 --- a/src/LightApp/resources/LightApp_msg_en.ts +++ b/src/LightApp/resources/LightApp_msg_en.ts @@ -851,6 +851,38 @@ The changes will be applied on the next application session. PREF_CLIPPING_SCALE Scale factor + + PREF_GROUP_RAY_TRACING + Ray tracing + + + PREF_RAY_TRACING_DEPTH + Depth + + + PREF_RAY_TRACING_REFLECTION + Specular reflections + + + PREF_RAY_TRACING_ANTIALIASING + Adaptive anti-aliasing + + + PREF_RAY_TRACING_SHADOW + Shadows rendering + + + PREF_RAY_TRACING_TRANS_SHADOW + Transparent shadow + + + PREF_GROUP_LIGHT + Light source + + + PREF_LIGHT_COLOR + Color + TOT_CLOSE Close diff --git a/src/LightApp/resources/LightApp_msg_fr.ts b/src/LightApp/resources/LightApp_msg_fr.ts index 526ecd7d2..63b93ab94 100755 --- a/src/LightApp/resources/LightApp_msg_fr.ts +++ b/src/LightApp/resources/LightApp_msg_fr.ts @@ -851,6 +851,38 @@ Les modifications seront appliquées à la prochaine session. PREF_CLIPPING_SCALE Facteur d'échelle + + PREF_GROUP_RAY_TRACING + Ray tracing + + + PREF_RAY_TRACING_DEPTH + Depth + + + PREF_RAY_TRACING_REFLECTION + Specular reflections + + + PREF_RAY_TRACING_ANTIALIASING + Adaptive anti-aliasing + + + PREF_RAY_TRACING_SHADOW + Shadows rendering + + + PREF_RAY_TRACING_TRANS_SHADOW + Transparent shadow + + + PREF_GROUP_LIGHT + Light source + + + PREF_LIGHT_COLOR + Color + TOT_CLOSE Fermer diff --git a/src/LightApp/resources/LightApp_msg_ja.ts b/src/LightApp/resources/LightApp_msg_ja.ts index 29a70c646..084e385be 100644 --- a/src/LightApp/resources/LightApp_msg_ja.ts +++ b/src/LightApp/resources/LightApp_msg_ja.ts @@ -851,6 +851,38 @@ CEA/DEN, CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITASPREF_CLIPPING_SCALE スケールファクタ + + PREF_GROUP_RAY_TRACING + Ray tracing + + + PREF_RAY_TRACING_DEPTH + Depth + + + PREF_RAY_TRACING_REFLECTION + Specular reflections + + + PREF_RAY_TRACING_ANTIALIASING + Adaptive anti-aliasing + + + PREF_RAY_TRACING_SHADOW + Shadows rendering + + + PREF_RAY_TRACING_TRANS_SHADOW + Transparent shadow + + + PREF_GROUP_LIGHT + Light source + + + PREF_LIGHT_COLOR + Color + TOT_CLOSE 閉じる diff --git a/src/OCCViewer/CMakeLists.txt b/src/OCCViewer/CMakeLists.txt index 01e7473bb..8c4159c85 100755 --- a/src/OCCViewer/CMakeLists.txt +++ b/src/OCCViewer/CMakeLists.txt @@ -36,6 +36,7 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/ViewerData ${PROJECT_SOURCE_DIR}/src/ViewerTools ${PROJECT_SOURCE_DIR}/src/OpenGLUtils + ${PROJECT_SOURCE_DIR}/src/CAF ) # additional preprocessor / compiler flags @@ -45,7 +46,7 @@ ADD_DEFINITIONS(${QT_DEFINITIONS} ${CAS_DEFINITIONS} ${OGL_DEFINITIONS}) SET(_link_LIBRARIES ${OPENGL_LIBRARIES} ${QT_LIBRARIES} ${CAS_KERNEL} ${CAS_VIEWER} ${CAS_TKGeomAlgo} ${CAS_TKTopAlgo} ${CAS_TKG2d} ${CAS_TKOpenGl} - CASCatch qtx suit ViewerTools ViewerData OpenGLUtils + CASCatch qtx suit ViewerTools ViewerData OpenGLUtils caf ) # --- headers --- @@ -55,6 +56,9 @@ SET(_moc_HEADERS OCCViewer_AISSelector.h OCCViewer_AxialScaleDlg.h OCCViewer_ClippingDlg.h + OCCViewer_RayTracingDlg.h + OCCViewer_EnvTextureDlg.h + OCCViewer_LightSourceDlg.h OCCViewer_CreateRestoreViewDlg.h OCCViewer_CubeAxesDlg.h OCCViewer_FontWidget.h @@ -141,6 +145,9 @@ SET(_other_RESOURCES resources/occ_view_triedre.png resources/occ_view_zoom.png resources/occ_view_zooming_style_switch.png + resources/occ_view_ray_tracing.png + resources/occ_view_env_texture.png + resources/occ_view_light_source.png ) # --- sources --- @@ -156,6 +163,9 @@ SET(_other_SOURCES OCCViewer_AISSelector.cxx OCCViewer_AxialScaleDlg.cxx OCCViewer_ClippingDlg.cxx + OCCViewer_RayTracingDlg.cxx + OCCViewer_EnvTextureDlg.cxx + OCCViewer_LightSourceDlg.cxx OCCViewer_ClipPlane.cxx OCCViewer_CreateRestoreViewDlg.cxx OCCViewer_CubeAxesDlg.cxx diff --git a/src/OCCViewer/OCCViewer_EnvTextureDlg.cxx b/src/OCCViewer/OCCViewer_EnvTextureDlg.cxx new file mode 100644 index 000000000..d1b0b35a8 --- /dev/null +++ b/src/OCCViewer/OCCViewer_EnvTextureDlg.cxx @@ -0,0 +1,237 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// internal includes +#include "OCCViewer_EnvTextureDlg.h" +#include "OCCViewer_ViewWindow.h" +#include "OCCViewer_ViewPort3d.h" +#include "OCCViewer_ViewFrame.h" + +// GUI includes +#include + +// OCCT includes +#include + +// QT Includes +#include +#include +#include +#include +#include +#include + +/*! + \class OCCViewer_EnvTextureDlg + \brief Dialog allowing to assign parameters of environment texture +*/ + +/*! + \brief Constructor + \param view - parent widget +*/ +OCCViewer_EnvTextureDlg::OCCViewer_EnvTextureDlg( OCCViewer_ViewWindow* view ) + :QDialog( view ) +{ + + // get current view frame (OCCViewer_ViewWindow->QFrame->OCCViewer_ViewFrame) + myViewFrame = dynamic_cast( view->parent()->parent() ); + myView3d = view->getViewPort()->getView(); + + setObjectName( "OCCViewer_EnvTextureDlg" ); + setWindowTitle( tr( "ENV_TEXTURE" ) ); + setModal( false ); + + setAttribute( Qt::WA_DeleteOnClose, true ); + + // Create layout for this dialog + QVBoxLayout* dlglayout = new QVBoxLayout( this ); + dlglayout->setSpacing( 6 ); + dlglayout->setMargin( 11 ); + + // Create "Environment texture" group + + myEnvTextureGroup = new QGroupBox( tr( "ENV_TEXTURE" ) ); + myEnvTextureGroup->setCheckable( true ); + + QGridLayout* envTextureLayout = new QGridLayout( myEnvTextureGroup ); + envTextureLayout->setSpacing( 6 ); + envTextureLayout->setMargin( 11 ); + + myEnvTextureId = new QComboBox(); + myEnvTextureId->addItem( tr( "ENV_CLOUDS" ) ); + myEnvTextureId->addItem( tr( "ENV_CV" ) ); + myEnvTextureId->addItem( tr( "ENV_MEDIT" ) ); + myEnvTextureId->addItem( tr( "ENV_PEARL" ) ); + myEnvTextureId->addItem( tr( "ENV_SKY1" ) ); + myEnvTextureId->addItem( tr( "ENV_SKY2" ) ); + myEnvTextureId->addItem( tr( "ENV_LINES" ) ); + myEnvTextureId->addItem( tr( "ENV_ROAD" ) ); + myEnvTextureId->addItem( tr( "ENV_CUSTOM" ) ); + myEnvTextureId->setMinimumWidth( 300 ); + + myEnvTextureName = new QLineEdit(); + myEnvTextureName->setVisible( false ); + myFileButton = new QPushButton(); + myFileButton->setText("..."); + myFileButton->setVisible( false ); + + envTextureLayout->addWidget( myEnvTextureId, 0, 0, 1, 2 ); + envTextureLayout->addWidget( myEnvTextureName, 1, 0 ); + envTextureLayout->addWidget( myFileButton, 1, 1 ); + + // Create "Buttons" group + + QGroupBox* groupButtons = new QGroupBox( this ); + QHBoxLayout* groupButtonsLayout = new QHBoxLayout( groupButtons ); + groupButtonsLayout->setSpacing( 6 ); + groupButtonsLayout->setMargin( 11 ); + + QPushButton* buttonClose = new QPushButton( tr( "BUT_CLOSE" ) ); + buttonClose->setDefault( true ); + + QPushButton* buttonHelp = new QPushButton( tr( "GEOM_BUT_HELP" ) ); + + groupButtonsLayout->addStretch(); + groupButtonsLayout->addWidget( buttonClose ); + groupButtonsLayout->addWidget( buttonHelp ); + + dlglayout->addWidget( myEnvTextureGroup ); + dlglayout->addWidget( groupButtons ); + + // Initializations + initParam(); + + // Signals and slots connections + connect( myEnvTextureGroup, SIGNAL( toggled(bool) ), this, SLOT( onEnvTexture(bool) ) ); + connect( myEnvTextureId, SIGNAL( currentIndexChanged(int) ), this, SLOT( onTextureChanged() ) ); + connect( myFileButton, SIGNAL( clicked() ), this, SLOT( onFileSelectionClicked() ) ); + connect( buttonClose, SIGNAL( clicked() ), this, SLOT( close() ) ); + connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( ClickOnHelp() ) ); +} + +/*! + \brief Destructor +*/ +OCCViewer_EnvTextureDlg::~OCCViewer_EnvTextureDlg() +{ +} + +QString OCCViewer_EnvTextureDlg::getName() +{ + // return the name of object + return QString( "OCCViewer_EnvTextureDlg" ); +} + +/*! + Initialization of initial values of widgets +*/ +void OCCViewer_EnvTextureDlg::initParam() +{ + Handle(Graphic3d_TextureEnv) aTexture = myView3d->TextureEnv(); + bool anIsTexture = !aTexture.IsNull(); + myEnvTextureGroup->setChecked( anIsTexture ); + if ( anIsTexture ) { + int aTextureId = myView3d->TextureEnv()->Name(); + myEnvTextureId->setCurrentIndex( aTextureId ); + if ( aTextureId == myEnvTextureId->count() - 1 ) { + TCollection_AsciiString aFileName; + aTexture->Path().SystemName( aFileName ); + myEnvTextureName->setText( QString( aFileName.ToCString() ) ); + myFileButton->setVisible( true ); + myEnvTextureName->setVisible( true ); + } + } +} + +/*! + SLOT on "Environment texture" group click +*/ +void OCCViewer_EnvTextureDlg::onEnvTexture( bool theIsChecked ) +{ + if ( theIsChecked ) + onTextureChanged(); + else { + Handle(Graphic3d_TextureEnv) aTexture; + setEnvTexture( aTexture, V3d_TEX_ALL ); + } +} + +/*! + SLOT on when user changed the texture +*/ +void OCCViewer_EnvTextureDlg::onTextureChanged() +{ + Handle(Graphic3d_TextureEnv) aTexture; + bool isCustom = myEnvTextureId->currentIndex() == myEnvTextureId->count()-1; + myEnvTextureName->setVisible( isCustom ); + myFileButton->setVisible( isCustom ); + if( isCustom ) { + if( myEnvTextureName->text().isEmpty() ) + onFileSelectionClicked(); + aTexture = new Graphic3d_TextureEnv( TCollection_AsciiString( myEnvTextureName->text().toStdString().c_str() ) ); + } + else { + myEnvTextureName->setText(""); + Graphic3d_NameOfTextureEnv aStandardTexture; + QList aTextures; + aTextures << Graphic3d_NOT_ENV_CLOUDS << Graphic3d_NOT_ENV_CV << Graphic3d_NOT_ENV_MEDIT + << Graphic3d_NOT_ENV_PEARL << Graphic3d_NOT_ENV_SKY1 << Graphic3d_NOT_ENV_SKY2 + << Graphic3d_NOT_ENV_LINES << Graphic3d_NOT_ENV_ROAD; + aTexture = new Graphic3d_TextureEnv( aTextures.at( myEnvTextureId->currentIndex() ) ); + } + setEnvTexture( aTexture, V3d_TEX_ENVIRONMENT ); +} + +/*! + SLOT on file selection button click +*/ +void OCCViewer_EnvTextureDlg::onFileSelectionClicked() +{ + QString selFile = QFileDialog::getOpenFileName( this,tr( "GEOM_SELECT_IMAGE" ),QString(), tr( "OCC_TEXTURE_FILES" ) ); + if ( !selFile.isEmpty() ) { + myEnvTextureName->setText( selFile ); + onTextureChanged(); + } +} + +/*! + SLOT on help button click: opens a help page +*/ +void OCCViewer_EnvTextureDlg::ClickOnHelp() +{ + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if ( app ) + app->onHelpContextModule( "GUI", "occ_3d_viewer_page.html", "env_texture" ); +} + +/*! + Sets current texture environment for all view in the viewer +*/ +void OCCViewer_EnvTextureDlg::setEnvTexture( Handle(Graphic3d_TextureEnv) theTexture, V3d_TypeOfSurfaceDetail theMode ) +{ + for ( int i = OCCViewer_ViewFrame::BOTTOM_RIGHT; i <= OCCViewer_ViewFrame::TOP_RIGHT; i++ ) { + if ( OCCViewer_ViewWindow* aViewWindow = myViewFrame->getView(i) ) { + Handle(V3d_View) aView = aViewWindow->getViewPort()->getView(); + aView->SetTextureEnv( theTexture ); + aView->SetSurfaceDetail( theMode ); + aView->Redraw(); + } + } +} diff --git a/src/OCCViewer/OCCViewer_EnvTextureDlg.h b/src/OCCViewer/OCCViewer_EnvTextureDlg.h new file mode 100644 index 000000000..0d172ff7f --- /dev/null +++ b/src/OCCViewer/OCCViewer_EnvTextureDlg.h @@ -0,0 +1,64 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef OCCVIEWER_ENVTEXTUREDLG_H +#define OCCVIEWER_ENVTEXTUREDLG_H + +#include "OCCViewer.h" +#include +#include + +class OCCViewer_ViewWindow; +class OCCViewer_ViewFrame; +class QGroupBox; +class QComboBox; +class QLineEdit; + +class OCCVIEWER_EXPORT OCCViewer_EnvTextureDlg : public QDialog +{ + Q_OBJECT + + public: + OCCViewer_EnvTextureDlg( OCCViewer_ViewWindow* ); + ~OCCViewer_EnvTextureDlg(); + + static QString getName(); + +private slots: + + void onEnvTexture( bool ); + void onTextureChanged(); + void onFileSelectionClicked(); + + void ClickOnHelp(); + +private: + void initParam(); + void setEnvTexture( Handle(Graphic3d_TextureEnv), V3d_TypeOfSurfaceDetail ); + + OCCViewer_ViewFrame* myViewFrame; + Handle(V3d_View) myView3d; + + QGroupBox* myEnvTextureGroup; + QComboBox* myEnvTextureId; + QLineEdit* myEnvTextureName; + QPushButton* myFileButton; +}; + +#endif // OCCVIEWER_ENVTEXTUREDLG_H diff --git a/src/OCCViewer/OCCViewer_LightSourceDlg.cxx b/src/OCCViewer/OCCViewer_LightSourceDlg.cxx new file mode 100644 index 000000000..ead1b69ce --- /dev/null +++ b/src/OCCViewer/OCCViewer_LightSourceDlg.cxx @@ -0,0 +1,431 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// internal includes +#include "OCCViewer_LightSourceDlg.h" +#include "OCCViewer_ViewWindow.h" +#include "OCCViewer_ViewModel.h" + +// GUI includes +#include +#include +#include +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include + +/*! + \class OCCViewer_LightSourceDlg + \brief Dialog allowing to assign parameters of light source +*/ + +/*! + \brief Constructor + \param view - parent widget + \param model - viewer +*/ +OCCViewer_LightSourceDlg::OCCViewer_LightSourceDlg( OCCViewer_ViewWindow* view, OCCViewer_Viewer* model ) + :QDialog( view ), + myModel( model ) +{ + setObjectName( "OCCViewer_LightSourceDlg" ); + setWindowTitle( tr( "LIGHT_SOURCE" ) ); + setModal( false ); + + setAttribute( Qt::WA_DeleteOnClose, true ); + + // Create layout for this dialog + QVBoxLayout* dlglayout = new QVBoxLayout( this ); + dlglayout->setSpacing( 6 ); dlglayout->setMargin( 11 ); + + QGroupBox* typeGroup = new QGroupBox( tr( "TYPE" ), this ); + QHBoxLayout* typeLayout = new QHBoxLayout( typeGroup ); + typeLayout->setSpacing( 6 ); typeLayout->setMargin( 11 ); + + myDirType = new QRadioButton( tr( "DIRECTIONAL" ), typeGroup ); + myPosType = new QRadioButton( tr( "POSITIONAL" ), typeGroup ); + + typeLayout->addWidget( myDirType ); + typeLayout->addWidget( myPosType ); + + myStackedLayout = new QStackedLayout(); + + const double min = -RealLast(); + const double max = RealLast(); + const int precision = 3; + + /********************** Directional light **********************/ + /* Controls for directional light: + Dx, Dy, Dz - direction + Headlight - headlight flag + Color - the color of a light source + */ + + QWidget* dirWidget = new QWidget( this ); + QVBoxLayout* dirLayout = new QVBoxLayout( dirWidget ); + dirLayout->setSpacing( 6 ); dirLayout->setMargin( 11 ); + + // Create "Direction" group + + const double dir_step = 0.1; + + QGroupBox* dirCoordGroup = new QGroupBox( tr( "DIRECTION" ), this ); + QHBoxLayout* dirCoordLayout = new QHBoxLayout( dirCoordGroup ); + dirCoordLayout->setSpacing( 6 ); dirCoordLayout->setMargin( 11 ); + + QLabel* dxLabel = new QLabel( tr("Dx:"), dirCoordGroup ); + myDx = new QtxDoubleSpinBox( min, max, dir_step, dirCoordGroup ); + myDx->setValue( 0.0 ); + myDx->setMinimumWidth( 80 ); + + QLabel* dyLabel = new QLabel( tr("Dy:"), dirCoordGroup ); + myDy = new QtxDoubleSpinBox( min, max, dir_step, dirCoordGroup ); + myDy->setValue( 0.0 ); + myDy->setMinimumWidth( 80 ); + + QLabel* dzLabel = new QLabel( tr("Dz:"), dirCoordGroup ); + myDz = new QtxDoubleSpinBox( min, max, dir_step, dirCoordGroup ); + myDz->setValue( -1.0 ); + myDz->setMinimumWidth( 80 ); + + dirCoordLayout->addWidget( dxLabel ); + dirCoordLayout->addWidget( myDx ); + dirCoordLayout->addWidget( dyLabel ); + dirCoordLayout->addWidget( myDy ); + dirCoordLayout->addWidget( dzLabel ); + dirCoordLayout->addWidget( myDz ); + + // Create "Parameters" group + + QGroupBox* dirParamGroup = new QGroupBox( dirWidget ); + QHBoxLayout* dirParamLayout = new QHBoxLayout( dirParamGroup ); + dirParamLayout->setSpacing( 6 ); dirParamLayout->setMargin( 11 ); + + myDirHeadLight = new QCheckBox( tr("HEADLIGHT"), dirParamGroup ); + myDirHeadLight->setChecked( false ); + + QLabel* aColorLabel = new QLabel( tr( "COLOR" ), dirParamGroup ); + myDirColor = new QtxColorButton( dirParamGroup ); + myDirColor->setColor( Qt::white ); + + dirParamLayout->addWidget( myDirHeadLight ); + dirParamLayout->addWidget( aColorLabel ); + dirParamLayout->addWidget( myDirColor ); + dirParamLayout->addStretch(); + + dirLayout->addWidget( dirCoordGroup ); + dirLayout->addWidget( dirParamGroup ); + + /********************** Positional light **********************/ + /* Controls for positional light: + X, Y, Z - position + Headlight - headlight flag + Color - the color of a light source + */ + + QWidget* posWidget = new QWidget( this ); + QVBoxLayout* posLayout = new QVBoxLayout( posWidget ); + posLayout->setSpacing( 6 ); posLayout->setMargin( 11 ); + + // Create "Position" group + + const double pos_step = 1.0; + + QGroupBox* posCoordGroup = new QGroupBox( tr( "POSITION" ), posWidget ); + QHBoxLayout* posCoordLayout = new QHBoxLayout( posCoordGroup ); + posCoordLayout->setSpacing( 6 ); posCoordLayout->setMargin( 11 ); + + QLabel* xLabel = new QLabel( tr("X:"), posCoordGroup ); + myX = new QtxDoubleSpinBox( min, max, pos_step, posCoordGroup ); + myX->setValue( 0.0 ); + myX->setMinimumWidth( 80 ); + + QLabel* yLabel = new QLabel( tr("Y:"), posCoordGroup ); + myY = new QtxDoubleSpinBox( min, max, pos_step, posCoordGroup ); + myY->setValue( 0.0 ); + myY->setMinimumWidth( 80 ); + + QLabel* zLabel = new QLabel( tr("Z:"), posCoordGroup ); + myZ = new QtxDoubleSpinBox( min, max, pos_step, posCoordGroup ); + myZ->setValue( 0.0 ); + myZ->setMinimumWidth( 80 ); + + posCoordLayout->addWidget( xLabel ); + posCoordLayout->addWidget( myX ); + posCoordLayout->addWidget( yLabel ); + posCoordLayout->addWidget( myY ); + posCoordLayout->addWidget( zLabel ); + posCoordLayout->addWidget( myZ ); + + // Create "Parameters" group + + QGroupBox* posParamGroup = new QGroupBox( posWidget ); + QHBoxLayout* posParamLayout = new QHBoxLayout( posParamGroup ); + posParamLayout->setSpacing( 6 ); posParamLayout->setMargin( 11 ); + + myPosHeadLight = new QCheckBox( tr("HEADLIGHT"), posParamGroup ); + myPosHeadLight->setChecked( false ); + + aColorLabel = new QLabel( tr( "COLOR" ), posParamGroup ); + myPosColor = new QtxColorButton( posParamGroup ); + myPosColor->setColor( Qt::white ); + + posParamLayout->addWidget( myPosHeadLight ); + posParamLayout->addWidget( aColorLabel ); + posParamLayout->addWidget( myPosColor ); + posParamLayout->addStretch(); + + posLayout->addWidget( posCoordGroup ); + posLayout->addWidget( posParamGroup ); + + // add widgets in the stacked layout + myStackedLayout->addWidget( dirWidget ); + myStackedLayout->addWidget( posWidget ); + + // Create "Buttons" group + + QGroupBox* buttonGroup = new QGroupBox( this ); + QHBoxLayout* buttonLayout = new QHBoxLayout( buttonGroup ); + buttonLayout->setSpacing( 6 ); + buttonLayout->setMargin( 11 ); + + QPushButton* okButton = new QPushButton( tr( "BUT_APPLY_AND_CLOSE" ), buttonGroup ); + okButton->setDefault( true ); + QPushButton* defaultButton = new QPushButton( tr( "BUT_DEFAULT" ), buttonGroup ); + QPushButton* closeButton = new QPushButton( tr( "BUT_CLOSE" ), buttonGroup ); + QPushButton* helpButton = new QPushButton( tr( "GEOM_BUT_HELP" ), buttonGroup ); + + buttonLayout->addWidget( okButton ); + buttonLayout->addWidget( defaultButton ); + buttonLayout->addStretch(); + buttonLayout->addWidget( closeButton ); + buttonLayout->addWidget( helpButton ); + + dlglayout->addWidget( typeGroup ); + dlglayout->addLayout( myStackedLayout ); + dlglayout->addWidget( buttonGroup ); + + this->setLayout( dlglayout ); + + // Initializations + initParam(); + isBusy = false; + + // Signals and slots connections + connect( myDirType, SIGNAL( clicked( bool ) ), this, SLOT( onTypeChanged() ) ); + connect( myPosType, SIGNAL( clicked( bool ) ), this, SLOT( onTypeChanged() ) ); + + connect( myDx, SIGNAL( valueChanged( double ) ), this, SLOT( onDirChanged() ) ); + connect( myDy, SIGNAL( valueChanged( double ) ), this, SLOT( onDirChanged() ) ); + connect( myDz, SIGNAL( valueChanged( double ) ), this, SLOT( onDirChanged() ) ); + connect( myDirHeadLight, SIGNAL( clicked( bool ) ), this, SLOT( onDirChanged() ) ); + connect( myDirColor, SIGNAL( changed( QColor ) ), this, SLOT( onDirChanged() ) ); + + connect( myX, SIGNAL( valueChanged( double ) ), this, SLOT( onPosChanged() ) ); + connect( myY, SIGNAL( valueChanged( double ) ), this, SLOT( onPosChanged() ) ); + connect( myZ, SIGNAL( valueChanged( double ) ), this, SLOT( onPosChanged() ) ); + connect( myPosHeadLight, SIGNAL( clicked( bool ) ), this, SLOT( onPosChanged() ) ); + connect( myPosColor, SIGNAL( changed( QColor ) ), this, SLOT( onPosChanged() ) ); + + connect( okButton, SIGNAL( clicked() ), this, SLOT( ClickOnOk() ) ); + connect( defaultButton, SIGNAL( clicked() ), this, SLOT( ClickOnDefault() ) ); + connect( closeButton, SIGNAL( clicked() ), this, SLOT( ClickOnClose() ) ); + connect( helpButton, SIGNAL( clicked() ), this, SLOT( ClickOnHelp() ) ); + + resize( minimumSizeHint() ); +} + +/*! + \brief Destructor +*/ +OCCViewer_LightSourceDlg::~OCCViewer_LightSourceDlg() +{ + ( myInType == V3d_DIRECTIONAL ) ? myModel->getViewer3d()->DelLight( myPosLight ) : + myModel->getViewer3d()->DelLight( myDirLight ); +} + +QString OCCViewer_LightSourceDlg::getName() +{ + // return the name of object + return QString( "OCCViewer_LightSourceDlg" ); +} + +/*! + Initialization of initial values of widgets +*/ +void OCCViewer_LightSourceDlg::initParam( bool theIsDefault ) +{ + Handle(V3d_Light) aLight; + myModel->getViewer3d()->InitDefinedLights(); + while ( myModel->getViewer3d()->MoreDefinedLights() ) + { + aLight = myModel->getViewer3d()->DefinedLight(); + if ( aLight->Type() == V3d_DIRECTIONAL ) { + myDirLight = Handle(V3d_DirectionalLight)::DownCast( aLight ); + myPosLight = new V3d_PositionalLight( myModel->getViewer3d(), 0, 0, 0 ); + myDirType->setChecked( true ); + myStackedLayout->setCurrentIndex(0); + break; + } + if ( aLight->Type() == V3d_POSITIONAL ) { + myPosLight = Handle(V3d_PositionalLight)::DownCast( aLight ); + myDirLight = new V3d_DirectionalLight( myModel->getViewer3d() ); + myPosType->setChecked( true ); + myStackedLayout->setCurrentIndex(1); + break; + } + myModel->getViewer3d()->NextDefinedLights(); + } + + double aX, aY, aZ; + Quantity_Color aColor = aLight->Color(); + if( myDirType->isChecked() ) { + myDirColor->setColor( CAF_Tools::color( aColor ) ); + myDirLight->Direction( aX, aY, aZ ); + myDx->setValue( aX ); + myDy->setValue( aY ); + myDz->setValue( aZ ); + myDirHeadLight->setChecked( myDirLight->Headlight() ); + } + else if( myPosType->isChecked() ) { + myPosColor->setColor( CAF_Tools::color( aColor ) ); + myPosLight->Position( aX, aY, aZ ); + myX->setValue( aX ); + myY->setValue( aY ); + myZ->setValue( aZ ); + myPosHeadLight->setChecked( myPosLight->Headlight() ); + } + + if ( !theIsDefault ) { + myInX = aX; myInY = aY; myInZ = aZ; + myInColor = aColor; + myInHeadLight = aLight->Headlight(); + myInType = aLight->Type(); + } +} + +/*! + SLOT: called on type of light source changed +*/ +void OCCViewer_LightSourceDlg::onTypeChanged() +{ + if( isBusy ) + return; + myStackedLayout->setCurrentIndex( myPosType->isChecked() ); + if( myPosType->isChecked() ) { + myModel->getViewer3d()->SetLightOff( myDirLight ); + onPosChanged(); + } + else if( myDirType->isChecked() ) { + myModel->getViewer3d()->SetLightOff( myPosLight ); + onDirChanged(); + } +} + +/*! + SLOT: called on value of directional light source changed +*/ +void OCCViewer_LightSourceDlg::onDirChanged() +{ + if( isBusy ) + return; + myModel->getViewer3d()->SetLightOff( myDirLight ); + if ( !( myDx->value() == 0 && myDy->value() == 0 && myDz->value() == 0 ) ) { + myDirLight->SetDirection( myDx->value(), myDy->value(), myDz->value() ); + myDirLight->SetColor( CAF_Tools::color( myDirColor->color() ) ); + myDirLight->SetHeadlight( myDirHeadLight->isChecked() ); + myModel->getViewer3d()->SetLightOn( myDirLight ); + } + myModel->getViewer3d()->UpdateLights(); +} + +/*! + SLOT: called on value of positional light source changed +*/ +void OCCViewer_LightSourceDlg::onPosChanged() +{ + if( isBusy ) + return; + myModel->getViewer3d()->SetLightOff( myPosLight ); + myPosLight->SetPosition( myX->value(), myY->value(), myZ->value() ); + myPosLight->SetColor( CAF_Tools::color( myPosColor->color() ) ); + myPosLight->SetHeadlight( myPosHeadLight->isChecked() ); + myModel->getViewer3d()->SetLightOn( myPosLight ); + myModel->getViewer3d()->UpdateLights(); +} + +/*! + \brief SLOT on "Apply and Close" button click: sets current light source and closes dialog +*/ +void OCCViewer_LightSourceDlg::ClickOnOk() +{ + // need save a current type for deleting other light when dialog will be closed + myInType = myDirType->isChecked() ? V3d_DIRECTIONAL : V3d_POSITIONAL; + close(); +} + +/*! + \brief SLOT on "Default" button click: sets default light source +*/ +void OCCViewer_LightSourceDlg::ClickOnDefault() +{ + isBusy = true; + myModel->setDefaultLights(); + initParam( true ); + myModel->getViewer3d()->UpdateLights(); + isBusy = false; +} + +/*! + \brief SLOT on "Close" button click: sets initial light source and closes dialog +*/ +void OCCViewer_LightSourceDlg::ClickOnClose() +{ + if( myInType == V3d_DIRECTIONAL ) { + myDirLight->SetDirection( myInX, myInY, myInZ ); + myDirLight->SetColor( myInColor ); + myDirLight->SetHeadlight( myInHeadLight ); + myModel->getViewer3d()->SetLightOn( myDirLight ); + } + else { + myPosLight->SetPosition( myInX, myInY, myInZ ); + myPosLight->SetColor( myInColor ); + myPosLight->SetHeadlight( myInHeadLight ); + myModel->getViewer3d()->SetLightOn( myPosLight ); + } + close(); +} + +/*! + \brief SLOT on help button click: opens a help page +*/ +void OCCViewer_LightSourceDlg::ClickOnHelp() +{ + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if ( app ) + app->onHelpContextModule( "GUI", "occ_3d_viewer_page.html", "light_source" ); +} diff --git a/src/OCCViewer/OCCViewer_LightSourceDlg.h b/src/OCCViewer/OCCViewer_LightSourceDlg.h new file mode 100644 index 000000000..7cf62ff81 --- /dev/null +++ b/src/OCCViewer/OCCViewer_LightSourceDlg.h @@ -0,0 +1,93 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef OCCVIEWER_LIGHTSOURCEDLG_H +#define OCCVIEWER_LIGHTSOURCEDLG_H + +#include "OCCViewer.h" +#include +#include +#include +#include + +class OCCViewer_ViewWindow; +class OCCViewer_Viewer; +class QtxDoubleSpinBox; +class QtxColorButton; +class QPushButton; +class QCheckBox; +class QRadioButton; +class QStackedLayout; + +class OCCVIEWER_EXPORT OCCViewer_LightSourceDlg: public QDialog +{ + Q_OBJECT + +public: + OCCViewer_LightSourceDlg( OCCViewer_ViewWindow*, OCCViewer_Viewer* ); + ~OCCViewer_LightSourceDlg(); + + static QString getName(); + +protected slots: + +private slots: + void onTypeChanged(); + void onDirChanged(); + void onPosChanged(); + + void ClickOnOk(); + void ClickOnDefault(); + void ClickOnClose(); + void ClickOnHelp(); + +private: + void initParam( bool theIsDefault = false ); + + OCCViewer_Viewer* myModel; + + Handle(V3d_DirectionalLight) myDirLight; + Handle(V3d_PositionalLight) myPosLight; + + QRadioButton* myDirType; + QRadioButton* myPosType; + + QStackedLayout* myStackedLayout; + + QtxDoubleSpinBox* myDx; + QtxDoubleSpinBox* myDy; + QtxDoubleSpinBox* myDz; + QCheckBox* myDirHeadLight; + QtxColorButton* myDirColor; + + QtxDoubleSpinBox* myX; + QtxDoubleSpinBox* myY; + QtxDoubleSpinBox* myZ; + QCheckBox* myPosHeadLight; + QtxColorButton* myPosColor; + + double myInX, myInY, myInZ; + bool myInHeadLight; + Quantity_Color myInColor; + V3d_TypeOfLight myInType; + + bool isBusy; +}; + +#endif // OCCVIEWER_LIGHTSOURCEDLG_H diff --git a/src/OCCViewer/OCCViewer_RayTracingDlg.cxx b/src/OCCViewer/OCCViewer_RayTracingDlg.cxx new file mode 100644 index 000000000..11a6d017a --- /dev/null +++ b/src/OCCViewer/OCCViewer_RayTracingDlg.cxx @@ -0,0 +1,188 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// internal includes +#include "OCCViewer_RayTracingDlg.h" +#include "OCCViewer_ViewWindow.h" +#include "OCCViewer_ViewPort3d.h" +#include "OCCViewer_ViewFrame.h" + +// GUI includes +#include +#include + +// QT Includes +#include +#include +#include +#include +#include + +/*! + \class OCCViewer_RayTracingDlg + \brief Dialog allowing to assign parameters of ray tracing +*/ + +/*! + \brief Constructor + \param view - parent widget +*/ +OCCViewer_RayTracingDlg::OCCViewer_RayTracingDlg( OCCViewer_ViewWindow* view ) + :QDialog( view ) +{ + // get current view frame (OCCViewer_ViewWindow->QFrame->OCCViewer_ViewFrame) + myViewFrame = dynamic_cast( view->parent()->parent() ); + myView3d = view->getViewPort()->getView(); + setObjectName( "OCCViewer_RayTracingDlg" ); + setWindowTitle( tr( "RAY_TRACING" ) ); + setModal( false ); + + setAttribute( Qt::WA_DeleteOnClose, true ); + + // Create layout for this dialog + QVBoxLayout* dlglayout = new QVBoxLayout( this ); + dlglayout->setSpacing( 6 ); + dlglayout->setMargin( 11 ); + + // Create "Ray tracing" group + + myRayTracingGroup = new QGroupBox( tr( "RAY_TRACING" ) ); + myRayTracingGroup->setCheckable( true ); + + QGridLayout* rayTracingLayout = new QGridLayout( myRayTracingGroup ); + rayTracingLayout->setSpacing( 6 ); + rayTracingLayout->setMargin( 11 ); + + myShadow = new QCheckBox( tr("SHADOW") ); + myReflection = new QCheckBox( tr("REFLECTION") ); + myAntialiasing = new QCheckBox( tr("ANTIALIASING") ); + myTransparentShadow = new QCheckBox( tr("TRANSPARENT_SHADOW") ); + QLabel* depthLabel = new QLabel( tr( "DEPTH" ) ); + myDepth = new QtxIntSpinBox( 1, 10 ); + + rayTracingLayout->addWidget( depthLabel, 0, 0 ); + rayTracingLayout->addWidget( myDepth, 0, 1 ); + rayTracingLayout->addWidget( myReflection, 1, 0 ); + rayTracingLayout->addWidget( myAntialiasing, 1, 1 ); + rayTracingLayout->addWidget( myShadow, 2, 0 ); + rayTracingLayout->addWidget( myTransparentShadow, 2, 1 ); + + // Create "Buttons" group + + QGroupBox* groupButtons = new QGroupBox( this ); + QHBoxLayout* groupButtonsLayout = new QHBoxLayout( groupButtons ); + groupButtonsLayout->setSpacing( 6 ); + groupButtonsLayout->setMargin( 11 ); + + QPushButton* buttonClose = new QPushButton( tr( "BUT_CLOSE" ) ); + buttonClose->setDefault( true ); + + QPushButton* buttonHelp = new QPushButton( tr( "GEOM_BUT_HELP" ) ); + + groupButtonsLayout->addStretch(); + groupButtonsLayout->addWidget( buttonClose ); + groupButtonsLayout->addWidget( buttonHelp ); + + dlglayout->addWidget( myRayTracingGroup ); + dlglayout->addWidget( groupButtons ); + + // Initializations + initParam(); + + // Signals and slots connections + connect( myRayTracingGroup, SIGNAL( toggled(bool) ), this, SLOT( onRayTracing(bool) ) ); + connect( myShadow, SIGNAL( toggled(bool) ), this, SLOT( onValueChanged() ) ); + connect( myReflection, SIGNAL( toggled(bool) ), this, SLOT( onValueChanged() ) ); + connect( myAntialiasing, SIGNAL( toggled(bool) ), this, SLOT( onValueChanged() ) ); + connect( myTransparentShadow, SIGNAL( toggled(bool) ), this, SLOT( onValueChanged() ) ); + connect( myDepth, SIGNAL( valueChanged(int) ), this, SLOT( onValueChanged() ) ); + connect( buttonClose, SIGNAL( clicked() ), this, SLOT( close() ) ) ; + connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( ClickOnHelp() ) ); +} + +/*! + \brief Destructor +*/ +OCCViewer_RayTracingDlg::~OCCViewer_RayTracingDlg() +{ +} + +QString OCCViewer_RayTracingDlg::getName() +{ + // return the name of object + return QString( "OCCViewer_RayTracingDlg" ); +} + +/*! + Initialization of initial values of widgets +*/ +void OCCViewer_RayTracingDlg::initParam() +{ + Graphic3d_RenderingParams aParams = myView3d->RenderingParams(); + myRayTracingGroup->setChecked( aParams.Method == Graphic3d_RM_RAYTRACING ); + myDepth->setValue( aParams.RaytracingDepth ); + myReflection->setChecked( aParams.IsReflectionEnabled ); + myAntialiasing->setChecked( aParams.IsAntialiasingEnabled ); + myShadow->setChecked( aParams.IsShadowEnabled ); + myTransparentShadow->setChecked( aParams.IsTransparentShadowEnabled ); +} + +/*! + SLOT: called on value of ray tracing changed +*/ +void OCCViewer_RayTracingDlg::onValueChanged() +{ + for ( int i = OCCViewer_ViewFrame::BOTTOM_RIGHT; i <= OCCViewer_ViewFrame::TOP_RIGHT; i++ ) { + if ( OCCViewer_ViewWindow* aViewWindow = myViewFrame->getView(i) ) { + Handle(V3d_View) aView = aViewWindow->getViewPort()->getView(); + Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams(); + aParams.IsShadowEnabled = myShadow->isChecked(); + aParams.IsReflectionEnabled = myReflection->isChecked(); + aParams.IsAntialiasingEnabled = myAntialiasing->isChecked(); + aParams.IsTransparentShadowEnabled = myTransparentShadow->isChecked(); + aParams.RaytracingDepth = myDepth->value(); + aView->Redraw(); + } + } +} + +/*! + SLOT on "Ray tracing" group click +*/ +void OCCViewer_RayTracingDlg::onRayTracing( bool theIsChecked ) +{ + for ( int i = OCCViewer_ViewFrame::BOTTOM_RIGHT; i <= OCCViewer_ViewFrame::TOP_RIGHT; i++ ) { + if ( OCCViewer_ViewWindow* aViewWindow = myViewFrame->getView(i) ) { + Handle(V3d_View) aView = aViewWindow->getViewPort()->getView(); + Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams(); + theIsChecked ? aParams.Method = Graphic3d_RM_RAYTRACING : aParams.Method = Graphic3d_RM_RASTERIZATION; + aView->Redraw(); + } + } +} + +/*! + SLOT on help button click: opens a help page +*/ +void OCCViewer_RayTracingDlg::ClickOnHelp() +{ + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if ( app ) + app->onHelpContextModule( "GUI", "occ_3d_viewer_page.html", "ray_tracing" ); +} diff --git a/src/OCCViewer/OCCViewer_RayTracingDlg.h b/src/OCCViewer/OCCViewer_RayTracingDlg.h new file mode 100644 index 000000000..9a7ba4903 --- /dev/null +++ b/src/OCCViewer/OCCViewer_RayTracingDlg.h @@ -0,0 +1,65 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef OCCVIEWER_RAYTRACINGDLG_H +#define OCCVIEWER_RAYTRACINGDLG_H + +#include "OCCViewer.h" +#include +#include + +class OCCViewer_ViewWindow; +class OCCViewer_ViewFrame; +class QCheckBox; +class QtxIntSpinBox; +class QGroupBox; + + +class OCCVIEWER_EXPORT OCCViewer_RayTracingDlg : public QDialog +{ + Q_OBJECT + + public: + OCCViewer_RayTracingDlg( OCCViewer_ViewWindow* ); + ~OCCViewer_RayTracingDlg(); + + static QString getName(); + +private slots: + + void onValueChanged(); + void onRayTracing(bool); + + void ClickOnHelp(); + +private: + void initParam(); + + OCCViewer_ViewFrame* myViewFrame; + Handle(V3d_View) myView3d; + + QGroupBox* myRayTracingGroup; + QtxIntSpinBox* myDepth; + QCheckBox* myReflection; + QCheckBox* myAntialiasing; + QCheckBox* myShadow; + QCheckBox* myTransparentShadow; +}; + +#endif // OCCVIEWER_RAYTRACINGDLG_H diff --git a/src/OCCViewer/OCCViewer_Utilities.cxx b/src/OCCViewer/OCCViewer_Utilities.cxx index 2818884c3..18e9096bc 100755 --- a/src/OCCViewer/OCCViewer_Utilities.cxx +++ b/src/OCCViewer/OCCViewer_Utilities.cxx @@ -36,6 +36,7 @@ // QT includes #include #include +#include Handle(Image_PixMap) OCCViewer_Utilities::imageToPixmap( const QImage& anImage ) { @@ -135,3 +136,14 @@ OCCViewer_ViewWindow::Mode2dType OCCViewer_Utilities::setViewer2DMode return anOldMode; } + +bool OCCViewer_Utilities::isDialogOpened( OCCViewer_ViewWindow* theView, const QString& theName ) +{ + bool isFound = false; + OCCViewer_ViewFrame* aViewFrame = dynamic_cast( theView->parent()->parent() ); + QList allDialogs = qFindChildren( aViewFrame ); + foreach ( QDialog* d, allDialogs ) + if ( d->objectName() == theName ) + isFound = true; + return isFound; +} diff --git a/src/OCCViewer/OCCViewer_Utilities.h b/src/OCCViewer/OCCViewer_Utilities.h index 125c0c458..484494543 100755 --- a/src/OCCViewer/OCCViewer_Utilities.h +++ b/src/OCCViewer/OCCViewer_Utilities.h @@ -55,6 +55,14 @@ public: setViewer2DMode( OCCViewer_Viewer* theViewer, const OCCViewer_ViewWindow::Mode2dType& theMode ); + /*! + * Find dialog in the current view frame by name + * \param theView an OCC view + * \param theName name of dialog + * \return true/false if dialog is opened/isn't opened + */ + static bool isDialogOpened( OCCViewer_ViewWindow* theView, const QString& theName ); + }; #endif // OCCVIEWER_UTILITIES_H diff --git a/src/OCCViewer/OCCViewer_ViewFrame.cxx b/src/OCCViewer/OCCViewer_ViewFrame.cxx index e4c3ec904..e3313a8b0 100644 --- a/src/OCCViewer/OCCViewer_ViewFrame.cxx +++ b/src/OCCViewer/OCCViewer_ViewFrame.cxx @@ -23,6 +23,7 @@ #include "OCCViewer_ViewFrame.h" #include "OCCViewer_ViewWindow.h" #include "OCCViewer_ViewModel.h" +#include "OCCViewer_ViewPort3d.h" #include #include @@ -169,10 +170,25 @@ void OCCViewer_ViewFrame::createSubViews() view->setDropDownButtons( dropDownButtons() ); connectViewSignals(view); view->setBackground(aModel->background(i)); + setSubViewParams( view ); } } } +//************************************************************************************** +void OCCViewer_ViewFrame::setSubViewParams( OCCViewer_ViewWindow* theView ) +{ + Handle(V3d_View) aView = theView->getViewPort()->getView(); + Handle(V3d_View) aMainView = myViews.at( MAIN_VIEW )->getViewPort()->getView(); + + // set ray tracing parameters + aView->ChangeRenderingParams() = aMainView->RenderingParams(); + + // set environment texture parameters + aView->SetTextureEnv( aMainView->TextureEnv() ); + aView->SetSurfaceDetail( aMainView->SurfaceDetail() ); +} + void OCCViewer_ViewFrame::splitSubViews() { if( mySplitMode == -1 ) diff --git a/src/OCCViewer/OCCViewer_ViewFrame.h b/src/OCCViewer/OCCViewer_ViewFrame.h index e7bb37726..ec4cfc773 100644 --- a/src/OCCViewer/OCCViewer_ViewFrame.h +++ b/src/OCCViewer/OCCViewer_ViewFrame.h @@ -172,6 +172,7 @@ private: void updateWindowTitle( OCCViewer_ViewWindow* theView ); void createSubViews(); void splitSubViews(); + void setSubViewParams( OCCViewer_ViewWindow* theView ); QList myViews; QGridLayout* myLayout; diff --git a/src/OCCViewer/OCCViewer_ViewModel.cxx b/src/OCCViewer/OCCViewer_ViewModel.cxx index 282cc5721..fe2546853 100755 --- a/src/OCCViewer/OCCViewer_ViewModel.cxx +++ b/src/OCCViewer/OCCViewer_ViewModel.cxx @@ -36,6 +36,8 @@ #include "ViewerData_AISShape.hxx" +#include "CAF_Tools.h" + #include #include "QtxActionToolMgr.h" @@ -73,6 +75,9 @@ #include +#include +#include + /*! Get data for supported background modes: gradient types, identifiers and supported image formats */ @@ -120,7 +125,7 @@ OCCViewer_Viewer::OCCViewer_Viewer( bool DisplayTrihedron) // init CasCade viewers myV3dViewer = OCCViewer_VService::CreateViewer( TCollection_ExtendedString("Viewer3d").ToExtString() ); //myV3dViewer->Init(); // to avoid creation of the useless perspective view (see OCCT issue 0024267) - myV3dViewer->SetDefaultLights(); + setDefaultLights(); // init selector myAISContext = new AIS_InteractiveContext( myV3dViewer ); @@ -1083,6 +1088,33 @@ void OCCViewer_Viewer::performSelectionChanged() emit selectionChanged(); } +/* + * Defines default lights + */ +void OCCViewer_Viewer::setDefaultLights() +{ + // clear all light sources + myV3dViewer->InitDefinedLights(); + while ( myV3dViewer->MoreDefinedLights() ) + { + myV3dViewer->DelLight( myV3dViewer->DefinedLight() ); + myV3dViewer->InitDefinedLights(); + } + + // get light source parameters from preferences + QColor aColor = SUIT_Session::session()->resourceMgr()->colorValue( "OCCViewer", "light_color", QColor( 0, 0, 0 ) ); + double aDx = SUIT_Session::session()->resourceMgr()->doubleValue( "OCCViewer", "light_dx", 0.0 ); + double aDy = SUIT_Session::session()->resourceMgr()->doubleValue( "OCCViewer", "light_dy", 0.0 ); + double aDz = SUIT_Session::session()->resourceMgr()->doubleValue( "OCCViewer", "light_dz", -1.0 ); + + Handle(V3d_DirectionalLight) aLight = + new V3d_DirectionalLight( myV3dViewer, V3d_Zneg, CAF_Tools::color( aColor ).Name(), Standard_True ); + if( !( aDx == 0 && aDy == 0 && aDz == 0 ) ) + aLight->SetDirection( aDx, aDy, aDz ); + myV3dViewer->SetLightOn( aLight ); + myV3dViewer->SetLightOn( new V3d_AmbientLight( myV3dViewer ) ); +} + /*! Hilights/unhilights object in viewer \param obj - object to be updated diff --git a/src/OCCViewer/OCCViewer_ViewModel.h b/src/OCCViewer/OCCViewer_ViewModel.h index a8eba563e..09d071fce 100755 --- a/src/OCCViewer/OCCViewer_ViewModel.h +++ b/src/OCCViewer/OCCViewer_ViewModel.h @@ -100,6 +100,8 @@ public: void performSelectionChanged(); // emit signal selectionChanged + void setDefaultLights(); + QColor backgroundColor() const; // obsolete void setBackgroundColor( const QColor& ); // obsolete Qtx::BackgroundData background() const; diff --git a/src/OCCViewer/OCCViewer_ViewPort3d.cxx b/src/OCCViewer/OCCViewer_ViewPort3d.cxx index cc6d7bf5a..5e927fbb3 100755 --- a/src/OCCViewer/OCCViewer_ViewPort3d.cxx +++ b/src/OCCViewer/OCCViewer_ViewPort3d.cxx @@ -28,6 +28,8 @@ #include #include +#include +#include #include #include @@ -88,7 +90,7 @@ OCCViewer_ViewPort3d::OCCViewer_ViewPort3d( QWidget* parent, const Handle( V3d_V } #endif - setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background + setDefaultParams(); myCursor = NULL; } @@ -803,3 +805,26 @@ QCursor* OCCViewer_ViewPort3d::getDefaultCursor() const { return myCursor; } + +/* + * Set default parameters from preferences + */ +void OCCViewer_ViewPort3d::setDefaultParams() +{ + setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background + + // get ray tracing parameters from preferences + int aDepth = SUIT_Session::session()->resourceMgr()->integerValue( "OCCViewer", "rt_depth", 3 ); + bool aReflection = SUIT_Session::session()->resourceMgr()->booleanValue( "OCCViewer", "rt_reflection", true ); + bool anAntialiasing = SUIT_Session::session()->resourceMgr()->booleanValue( "OCCViewer", "rt_antialiasing", false ); + bool aShadow = SUIT_Session::session()->resourceMgr()->booleanValue( "OCCViewer", "rt_shadow", true ); + bool aTransparentShadow = SUIT_Session::session()->resourceMgr()->booleanValue( "OCCViewer", "rt_trans_shadow", true ); + + Graphic3d_RenderingParams& aParams = myActiveView->ChangeRenderingParams(); + aParams.RaytracingDepth = aDepth; + aParams.IsReflectionEnabled = aReflection; + aParams.IsAntialiasingEnabled = anAntialiasing; + aParams.IsShadowEnabled = aShadow; + aParams.IsTransparentShadowEnabled = aTransparentShadow; + myActiveView->Redraw(); +} diff --git a/src/OCCViewer/OCCViewer_ViewPort3d.h b/src/OCCViewer/OCCViewer_ViewPort3d.h index 7f8841a25..1413b76e9 100755 --- a/src/OCCViewer/OCCViewer_ViewPort3d.h +++ b/src/OCCViewer/OCCViewer_ViewPort3d.h @@ -122,6 +122,7 @@ private: bool setWindow( const Handle(V3d_View)& ); bool mapped( const Handle(V3d_View)& ) const; void updateBackground(); + void setDefaultParams(); private: Handle(V3d_View) myActiveView; diff --git a/src/OCCViewer/OCCViewer_ViewWindow.cxx b/src/OCCViewer/OCCViewer_ViewWindow.cxx index a0e96792b..d8c9de76b 100755 --- a/src/OCCViewer/OCCViewer_ViewWindow.cxx +++ b/src/OCCViewer/OCCViewer_ViewWindow.cxx @@ -34,6 +34,10 @@ #include "OCCViewer_AxialScaleDlg.h" #include "OCCViewer_CubeAxesDlg.h" #include "OCCViewer_ClippingDlg.h" +#include "OCCViewer_RayTracingDlg.h" +#include "OCCViewer_EnvTextureDlg.h" +#include "OCCViewer_LightSourceDlg.h" +#include "OCCViewer_Utilities.h" #include #include @@ -116,6 +120,9 @@ static QEvent* l_mbPressEvent = 0; #undef KeyPress #endif +// Enable ray tracing features +#define ENABLE_RAY_TRACING + const char* imageZoomCursor[] = { "32 32 3 1", ". c None", @@ -1446,6 +1453,28 @@ void OCCViewer_ViewWindow::createActions() // Synchronize View toolMgr()->registerAction( synchronizeAction(), SynchronizeId ); +#ifdef ENABLE_RAY_TRACING + // Ray tracing + aAction = new QtxAction( tr("MNU_RAY_TRACING"), aResMgr->loadPixmap( "OCCViewer", tr("ICON_OCCVIEWER_RAY_TRACING") ), + tr("MNU_RAY_TRACING"), 0, this ); + aAction->setStatusTip( tr("DSC_RAY_TRACING") ); + connect( aAction, SIGNAL( triggered() ), this, SLOT( onRayTracing() ) ); + toolMgr()->registerAction( aAction, RayTracingId ); + + // Environment texture + aAction = new QtxAction( tr("MNU_ENV_TEXTURE"), aResMgr->loadPixmap( "OCCViewer", tr("ICON_OCCVIEWER_ENV_TEXTURE") ), + tr("MNU_ENV_TEXTURE"), 0, this ); + aAction->setStatusTip( tr("DSC_ENV_TEXTURE") ); + connect( aAction, SIGNAL( triggered() ), this, SLOT( onEnvTexture() ) ); + toolMgr()->registerAction( aAction, EnvTextureId ); + + // Light source + aAction = new QtxAction( tr("MNU_LIGHT_SOURCE"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_LIGHT_SOURCE" ) ), + tr( "MNU_LIGHT_SOURCE" ), 0, this ); + aAction->setStatusTip( tr("DSC_LIGHT_SOURCE") ); + connect( aAction, SIGNAL( triggered() ), this, SLOT( onLightSource() ) ); + toolMgr()->registerAction( aAction, LightSourceId ); +#endif } /*! @@ -1535,6 +1564,11 @@ void OCCViewer_ViewWindow::createToolBar() toolMgr()->append( MaximizedId, tid ); toolMgr()->append( SynchronizeId, tid ); +#ifdef ENABLE_RAY_TRACING + toolMgr()->append( RayTracingId, tid ); + toolMgr()->append( EnvTextureId, tid ); + toolMgr()->append( LightSourceId, tid ); +#endif } /*! @@ -2232,17 +2266,20 @@ bool OCCViewer_ViewWindow::dumpViewToFormat( const QImage& img, const QString& fileName, const QString& format ) { + bool res = false; + QApplication::setOverrideCursor( Qt::WaitCursor ); if ( format != "PS" && format != "EPS") - return SUIT_ViewWindow::dumpViewToFormat( img, fileName, format ); + res = myViewPort->getView()->Dump( fileName.toStdString().c_str() ); Handle(Visual3d_View) a3dView = myViewPort->getView()->View(); if (format == "PS") - a3dView->Export(strdup(qPrintable(fileName)), Graphic3d_EF_PostScript); + res = a3dView->Export(strdup(qPrintable(fileName)), Graphic3d_EF_PostScript); else if (format == "EPS") - a3dView->Export(strdup(qPrintable(fileName)), Graphic3d_EF_EnhPostScript); + res = a3dView->Export(strdup(qPrintable(fileName)), Graphic3d_EF_EnhPostScript); - return true; + QApplication::restoreOverrideCursor(); + return res; } @@ -2540,6 +2577,58 @@ QString OCCViewer_ViewWindow::getVisualParameters() data << QString( "gtTickmarkLengthX=%1" ).arg( params.gtTickmarkLengthX ); data << QString( "gtTickmarkLengthY=%1" ).arg( params.gtTickmarkLengthY ); data << QString( "gtTickmarkLengthZ=%1" ).arg( params.gtTickmarkLengthZ ); + + // ray tracing parameters + Graphic3d_RenderingParams rendParams = this->getViewPort()->getView()->RenderingParams(); + if ( rendParams.Method == Graphic3d_RM_RAYTRACING ) { + QString RayTracing = "rayTracing="; + RayTracing += QString( "rtDepth~%1;" ).arg( rendParams.RaytracingDepth ); + RayTracing += QString( "rtReflection~%1;" ).arg( rendParams.IsReflectionEnabled ); + RayTracing += QString( "rtAntialiasing~%1;" ).arg( rendParams.IsAntialiasingEnabled ); + RayTracing += QString( "rtShadow~%1;" ).arg( rendParams.IsShadowEnabled ); + RayTracing += QString( "rtTransShadow~%1;" ).arg( rendParams.IsTransparentShadowEnabled ); + data << RayTracing; + } + + // environment texture parameters + Handle(Graphic3d_TextureEnv) aTexture = this->getViewPort()->getView()->TextureEnv(); + if ( !aTexture.IsNull() ) { + QString EnvTexture = "envTexture="; + if ( aTexture->Name() == Graphic3d_NOT_ENV_UNKNOWN ) { + TCollection_AsciiString aFileName; + aTexture->Path().SystemName( aFileName ); + EnvTexture += QString( "etFile~%1;" ).arg( aFileName.ToCString() ); + } + else + EnvTexture += QString( "etNumber~%1;" ).arg( aTexture->Name() ); + data << EnvTexture; + } + + // light source parameters + myModel->getViewer3d()->InitDefinedLights(); + while ( myModel->getViewer3d()->MoreDefinedLights() ) + { + Handle(V3d_Light) aLight = myModel->getViewer3d()->DefinedLight(); + if ( aLight->Type() != V3d_AMBIENT ) { + QString LightSource = QString( "lightSource=" ); + LightSource += QString( "lightType~%1;" ).arg( aLight->Type() ); + double aX, aY, aZ; + if ( aLight->Type() == V3d_DIRECTIONAL ) + Handle(V3d_DirectionalLight)::DownCast( aLight )->Direction( aX, aY, aZ ); + else if ( aLight->Type() == V3d_POSITIONAL ) + Handle(V3d_PositionalLight)::DownCast( aLight )->Position( aX, aY, aZ ); + LightSource += QString( "lightX~%1;" ).arg( aX ); + LightSource += QString( "lightY~%1;" ).arg( aY ); + LightSource += QString( "lightZ~%1;" ).arg( aZ ); + LightSource += QString( "lightColorR~%1;" ).arg( aLight->Color().Red() ); + LightSource += QString( "lightColorG~%1;" ).arg( aLight->Color().Green() ); + LightSource += QString( "lightColorB~%1;" ).arg( aLight->Color().Blue() ); + LightSource += QString( "lightHeadlight~%1;" ).arg( aLight->Headlight() ); + data << LightSource; + } + myModel->getViewer3d()->NextDefinedLights(); + } + QString bg = Qtx::backgroundToString( background() ).replace( "=", "$" ); data << QString( "background=%1" ).arg( bg ); @@ -2658,6 +2747,81 @@ void OCCViewer_ViewWindow::setVisualParameters( const QString& parameters ) else if ( paramName == "gtTickmarkLengthX" ) params.gtTickmarkLengthX = paramValue.toInt(); else if ( paramName == "gtTickmarkLengthY" ) params.gtTickmarkLengthY = paramValue.toInt(); else if ( paramName == "gtTickmarkLengthZ" ) params.gtTickmarkLengthZ = paramValue.toInt(); + else if ( paramName == "rayTracing" ) + { + Graphic3d_RenderingParams& rendParams = this->getViewPort()->getView()->ChangeRenderingParams(); + rendParams.Method = Graphic3d_RM_RAYTRACING; + QStringList rtData = paramValue.split( ';' ); + foreach( QString rtParam, rtData ) + { + QString rt_paramName = rtParam.section( '~', 0, 0 ).trimmed(); + QString rt_paramValue = rtParam.section( '~', 1, 1 ).trimmed(); + if ( rt_paramName == "rtDepth" ) rendParams.RaytracingDepth = rt_paramValue.toInt(); + else if ( rt_paramName == "rtReflection" ) rendParams.IsReflectionEnabled = rt_paramValue.toInt(); + else if ( rt_paramName == "rtAntialiasing" ) rendParams.IsAntialiasingEnabled = rt_paramValue.toInt(); + else if ( rt_paramName == "rtShadow" ) rendParams.IsShadowEnabled = rt_paramValue.toInt(); + else if ( rt_paramName == "rtTransShadow" ) rendParams.IsTransparentShadowEnabled = rt_paramValue.toInt(); + } + } + else if ( paramName == "envTexture" ) + { + Handle(Graphic3d_TextureEnv) aTexture; + QStringList etData = paramValue.split( ';' ); + foreach( QString etParam, etData ) + { + QString et_paramName = etParam.section( '~', 0, 0 ).trimmed(); + QString et_paramValue = etParam.section( '~', 1, 1 ).trimmed(); + if ( et_paramName == "etNumber" ) + aTexture = new Graphic3d_TextureEnv( Graphic3d_NameOfTextureEnv( et_paramValue.toInt() ) ); + else if ( et_paramName == "etFile" ) + aTexture = new Graphic3d_TextureEnv( TCollection_AsciiString( et_paramValue.toStdString().c_str() ) ); + Handle(V3d_View) aView = this->getViewPort()->getView(); + aView->SetTextureEnv( aTexture ); + aView->SetSurfaceDetail( V3d_TEX_ENVIRONMENT ); + } + } + else if ( paramName == "lightSource" ) + { + myModel->getViewer3d()->InitDefinedLights(); + while ( myModel->getViewer3d()->MoreDefinedLights() ) + { + Handle(V3d_Light) aLight = myModel->getViewer3d()->DefinedLight(); + if( aLight->Type() != V3d_AMBIENT ) + myModel->getViewer3d()->DelLight( aLight ); + myModel->getViewer3d()->NextDefinedLights(); + } + double aX, aY, aZ; + double cR, cG, cB; + V3d_TypeOfLight aType; + bool isHeadlight; + QStringList lsData = paramValue.split( ';' ); + foreach( QString lsParam, lsData ) + { + QString ls_paramName = lsParam.section( '~', 0, 0 ).trimmed(); + QString ls_paramValue = lsParam.section( '~', 1, 1 ).trimmed(); + if ( ls_paramName == "lightType" ) aType = V3d_TypeOfLight( ls_paramValue.toInt() ); + else if ( ls_paramName == "lightX" ) aX = ls_paramValue.toDouble(); + else if ( ls_paramName == "lightY" ) aY = ls_paramValue.toDouble(); + else if ( ls_paramName == "lightZ" ) aZ = ls_paramValue.toDouble(); + else if ( ls_paramName == "lightColorR" ) cR = ls_paramValue.toDouble(); + else if ( ls_paramName == "lightColorG" ) cG = ls_paramValue.toDouble(); + else if ( ls_paramName == "lightColorB" ) cB = ls_paramValue.toDouble(); + else if ( ls_paramName == "lightHeadlight" ) isHeadlight = ls_paramValue.toInt(); + } + Quantity_Color aColor = Quantity_Color( cR, cG, cB, Quantity_TOC_RGB ); + if( aType == V3d_DIRECTIONAL ) { + Handle(V3d_DirectionalLight) aLight = new V3d_DirectionalLight( myModel->getViewer3d() ); + aLight->SetDirection( aX, aY, aZ ); + aLight->SetColor( aColor ); + aLight->SetHeadlight( isHeadlight ); + myModel->getViewer3d()->SetLightOn( aLight ); + } + else if( aType == V3d_POSITIONAL ) { + Handle(V3d_PositionalLight) aLight = new V3d_PositionalLight( myModel->getViewer3d(), aX, aY, aZ, aColor.Name() ); + aLight->SetHeadlight( isHeadlight ); + myModel->getViewer3d()->SetLightOn( aLight ); + } + } else if ( paramName == "background" ) { QString bg = paramValue.replace( "$", "=" ); bgData = Qtx::stringToBackground( bg ); @@ -3559,3 +3723,30 @@ void OCCViewer_ViewWindow::onClipping (bool theIsOn) } } } + +void OCCViewer_ViewWindow::onRayTracing() +{ + if( !OCCViewer_Utilities::isDialogOpened( this, OCCViewer_RayTracingDlg::getName() ) ) { + QDialog* aDlg = new OCCViewer_RayTracingDlg( this ); + if ( aDlg != NULL ) + aDlg->show(); + } +} + +void OCCViewer_ViewWindow::onEnvTexture() +{ + if( !OCCViewer_Utilities::isDialogOpened( this, OCCViewer_EnvTextureDlg::getName() ) ) { + QDialog* aDlg = new OCCViewer_EnvTextureDlg( this ); + if ( aDlg != NULL ) + aDlg->show(); + } +} + +void OCCViewer_ViewWindow::onLightSource() +{ + if( !OCCViewer_Utilities::isDialogOpened( this, OCCViewer_LightSourceDlg::getName() ) ) { + QDialog* aDlg = new OCCViewer_LightSourceDlg( this, myModel ); + if ( aDlg != NULL ) + aDlg->show(); + } +} diff --git a/src/OCCViewer/OCCViewer_ViewWindow.h b/src/OCCViewer/OCCViewer_ViewWindow.h index 51f6b92b0..a9f656257 100755 --- a/src/OCCViewer/OCCViewer_ViewWindow.h +++ b/src/OCCViewer/OCCViewer_ViewWindow.h @@ -151,7 +151,7 @@ public: SwitchInteractionStyleId, SwitchZoomingStyleId, SwitchPreselectionId, SwitchSelectionId, MaximizedId, SynchronizeId, ReturnTo3dViewId, - OrthographicId, PerspectiveId, StereoId, + OrthographicId, PerspectiveId, StereoId, RayTracingId, EnvTextureId, LightSourceId, UserId }; enum OperationType{ NOTHING, PANVIEW, ZOOMVIEW, ROTATE, @@ -305,6 +305,9 @@ public slots: virtual void onSwitchZoomingStyle( bool on ); virtual void onSwitchPreselection( bool on ); virtual void onSwitchSelection( bool on ); + virtual void onRayTracing(); + virtual void onEnvTexture(); + virtual void onLightSource(); virtual void activateSetRotationGravity(); virtual void activateSetRotationSelected( double theX, double theY, double theZ ); diff --git a/src/OCCViewer/resources/OCCViewer_images.ts b/src/OCCViewer/resources/OCCViewer_images.ts index ee8fbb6a0..d91f20aaf 100644 --- a/src/OCCViewer/resources/OCCViewer_images.ts +++ b/src/OCCViewer/resources/OCCViewer_images.ts @@ -151,5 +151,17 @@ ICON_OCCVIEWER_STEREO occ_view_stereo.png + + ICON_OCCVIEWER_RAY_TRACING + occ_view_ray_tracing.png + + + ICON_OCCVIEWER_ENV_TEXTURE + occ_view_env_texture.png + + + ICON_OCCVIEWER_LIGHT_SOURCE + occ_view_light_source.png + diff --git a/src/OCCViewer/resources/OCCViewer_msg_en.ts b/src/OCCViewer/resources/OCCViewer_msg_en.ts index 5c993519b..36cd063ca 100644 --- a/src/OCCViewer/resources/OCCViewer_msg_en.ts +++ b/src/OCCViewer/resources/OCCViewer_msg_en.ts @@ -276,6 +276,30 @@ DSC_RETURN_3D_VIEW Return to 3D view + + MNU_RAY_TRACING + Ray tracing + + + DSC_RAY_TRACING + Ray tracing + + + MNU_ENV_TEXTURE + Environment texture + + + DSC_ENV_TEXTURE + Environment texture + + + MNU_LIGHT_SOURCE + Light source + + + DSC_LIGHT_SOURCE + Light source + OCC_IMAGE_FILES Images Files (*.bmp *.png *.jpg *.jpeg *.eps *.ps) @@ -619,4 +643,113 @@ &Help + + OCCViewer_RayTracingDlg + + RAY_TRACING + Ray tracing + + + DEPTH + Depth + + + SHADOW + Shadows rendering + + + REFLECTION + Specular reflections + + + ANTIALIASING + Adaptive anti-aliasing + + + TRANSPARENT_SHADOW + Transparent shadow + + + + OCCViewer_EnvTextureDlg + + ENV_TEXTURE + Environment texture + + + ENV_CLOUDS + Clouds + + + ENV_CV + Cv + + + ENV_MEDIT + Medit + + + ENV_PEARL + Pearl + + + ENV_SKY1 + Sky1 + + + ENV_SKY2 + Sky2 + + + ENV_LINES + Lines + + + ENV_ROAD + Road + + + ENV_CUSTOM + Custom... + + + + OCCViewer_LightSourceDlg + + LIGHT_SOURCE + Light source + + + TYPE + Type + + + DIRECTIONAL + Directional + + + DIRECTION + Direction + + + POSITIONAL + Positional + + + POSITION + Position + + + COLOR + Color + + + HEADLIGHT + Headlight + + + BUT_DEFAULT + Default + + diff --git a/src/OCCViewer/resources/OCCViewer_msg_fr.ts b/src/OCCViewer/resources/OCCViewer_msg_fr.ts index e7b680e0b..b0fd983fc 100755 --- a/src/OCCViewer/resources/OCCViewer_msg_fr.ts +++ b/src/OCCViewer/resources/OCCViewer_msg_fr.ts @@ -275,6 +275,30 @@ DSC_RETURN_3D_VIEW Retour à la vue 3D + + MNU_RAY_TRACING + Ray tracing + + + DSC_RAY_TRACING + Ray tracing + + + MNU_ENV_TEXTURE + Environment texture + + + DSC_ENV_TEXTURE + Environment texture + + + MNU_LIGHT_SOURCE + Light source + + + DSC_LIGHT_SOURCE + Light source + OCC_IMAGE_FILES Fichiers images (*.bmp *.png *.jpg *.jpeg *.eps *.ps) @@ -618,4 +642,113 @@ Ai&de + + OCCViewer_RayTracingDlg + + RAY_TRACING + Ray tracing + + + DEPTH + Depth + + + SHADOW + Shadows rendering + + + REFLECTION + Specular reflections + + + ANTIALIASING + Adaptive anti-aliasing + + + TRANSPARENT_SHADOW + Transparent shadow + + + + OCCViewer_EnvTextureDlg + + ENV_TEXTURE + Environment texture + + + ENV_CLOUDS + Clouds + + + ENV_CV + Cv + + + ENV_MEDIT + Medit + + + ENV_PEARL + Pearl + + + ENV_SKY1 + Sky1 + + + ENV_SKY2 + Sky2 + + + ENV_LINES + Lines + + + ENV_ROAD + Road + + + ENV_CUSTOM + Custom... + + + + OCCViewer_LightSourceDlg + + LIGHT_SOURCE + Light source + + + TYPE + Type + + + DIRECTIONAL + Directional + + + DIRECTION + Direction + + + POSITIONAL + Positional + + + POSITION + Position + + + COLOR + Color + + + HEADLIGHT + Headlight + + + BUT_DEFAULT + Default + + diff --git a/src/OCCViewer/resources/OCCViewer_msg_ja.ts b/src/OCCViewer/resources/OCCViewer_msg_ja.ts index a98424954..c45ce44c6 100644 --- a/src/OCCViewer/resources/OCCViewer_msg_ja.ts +++ b/src/OCCViewer/resources/OCCViewer_msg_ja.ts @@ -272,6 +272,30 @@ MNU_RETURN_3D_VIEW 3D に戻る + + MNU_RAY_TRACING + Ray tracing + + + DSC_RAY_TRACING + Ray tracing + + + MNU_ENV_TEXTURE + Environment texture + + + DSC_ENV_TEXTURE + Environment texture + + + MNU_LIGHT_SOURCE + Light source + + + DSC_LIGHT_SOURCE + Light source + DSC_RETURN_3D_VIEW 3D view に戻る @@ -619,4 +643,113 @@ ヘルプ(&H) + + OCCViewer_RayTracingDlg + + RAY_TRACING + Ray tracing + + + DEPTH + Depth + + + SHADOW + Shadows rendering + + + REFLECTION + Specular reflections + + + ANTIALIASING + Adaptive anti-aliasing + + + TRANSPARENT_SHADOW + Transparent shadow + + + + OCCViewer_EnvTextureDlg + + ENV_TEXTURE + Environment texture + + + ENV_CLOUDS + Clouds + + + ENV_CV + Cv + + + ENV_MEDIT + Medit + + + ENV_PEARL + Pearl + + + ENV_SKY1 + Sky1 + + + ENV_SKY2 + Sky2 + + + ENV_LINES + Lines + + + ENV_ROAD + Road + + + ENV_CUSTOM + Custom... + + + + OCCViewer_LightSourceDlg + + LIGHT_SOURCE + Light source + + + TYPE + Type + + + DIRECTIONAL + Directional + + + DIRECTION + Direction + + + POSITIONAL + Positional + + + POSITION + Position + + + COLOR + Color + + + HEADLIGHT + Headlight + + + BUT_DEFAULT + Default + + diff --git a/src/OCCViewer/resources/occ_view_env_texture.png b/src/OCCViewer/resources/occ_view_env_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..e360a879f0763d566fac3b22b3e5005786c19e12 GIT binary patch literal 1050 zcmV+#1m*jQP)Px#24YJ`L;zd>ivYi}9>d81000SaNLh0L01FZT01FZU(%pXi00007bV*G`2j2=D z3I`|%piegd00WvyL_t(I%YBqvh*f12$A5dDGmN9vq#+uXi9>3}*g)VzD%6vi7YKtM zy1`IylI8f&g9Qd%9zvvg=qbvFpiH}vF9o4F1VxRv9x|L!6NhO=Pn$ktPzPV;Y zzTB~6ht=zKmOnZOKv2Vrk`{8^b76e^1#7ihOifMQ1db~5;NYP3Z`(yJj)(xW4zTcn zBp2GbC(VVV5RzO-3(xm&JpphVkleIG?>%R}-A5e9tlG2_Gs6ePc_k@#R>8h|a}y#` zr49fmfn*lYImfEaLqrjb9C`;4!Fx}VBs3Zg8jS|i)6+DYP1f!Ff>0z3fA}20dSC(= zodqn40w;=@(f9ZeqKb%;xj-{@v{Fw}2)@V(MS{4rN?lx*%}v0<2h@xZ3{l04k`;k= z*6E?RoKU2QO9?ImNdJOkQ?RJw#6;1HMA78f*ciDBWJMrzQXYiR$~>*i%dqo5%0p|m`yY7V#1aYX(2~u?2J5&k)+Fe}(i{VM4=u?1L zqG(QDuYa_#*=*f^a6c;!?I) z(bFgzI^5m;-ewVe9J6!JVaEQ=2tF@?(@2q^QV@K>*1u0<8rb{iaR7dYed|SrX3g@_ z?r!^d`C3c^>qmdZ$1$&Oe~o;>B931iWy^(=s0wQv<7~Zh0f4VU;Ga1DX_xBDW_D`U zkA2BG_H1~TJEkW&v0w@P6X$sM;M?5F)(va|GcJ!DVN!KuW^9&x#kDS)bLaDU-&#If z+E4GQ4T#GKE=7HTs$v#s)Vqn|n8{mwESe#(50$FHn(c3t9;s zD*tGi^GQ|mOkf}IRH+_Y_Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FZT01FZU(%pXi00007bV*G`2j2=C z3@Q@<+qm}t00R0+L_t(I%dON~Yg|vg$ffD+XoiB zu;6#I*7L&OGrM~pNqzsAV)fwo5xkN8E-AEF-OgBPC4_?kjrq@MeE-Qu&1Uo6 zJ;7bHo~7w!ga7pQKsnEILL0Eo5$B49T6fOJOo_yhJgz=8fW(%JdDAL zTGeB;>hsu$kB37lh1H6CtuBK&LFOq|6&#p&=5^rsP%uuib6)L$OH)Z+Xo}L37Mdj2 zC;QJo=phMbSrOYC?|LD}Sz^Pyun4}4DCPg)0K7aDTw3~*>nnXG#sWrb6@(vvbF_L1zu#$b_2vqm$&qn{mKit;&H;=M z1vj?ZTx&|Vu-q0}DJnL_YDtkLY;0{~%7P+`an>Ss{)rPilNIr^N7 z<4A;2Oc+Jz zU%Mc(?%F)C1biX>q307IPJ{dK(9}u)@u`!6Q8`AHIHOQ9aqY&O27Ut8fzN<%#lI|% zCxFwyTflLk`oNt6ZUJ530&o$C#edjHhk+M>SAZ$N-LE|G8}Ku*3?u-50fwQ?aph;q QrvLx|07*qoM6N<$f~NzY>;M1& literal 0 HcmV?d00001 diff --git a/src/OCCViewer/resources/occ_view_ray_tracing.png b/src/OCCViewer/resources/occ_view_ray_tracing.png new file mode 100644 index 0000000000000000000000000000000000000000..fc64a13418346b3e4b8cea26d75697b7d4bd962b GIT binary patch literal 660 zcmV;F0&D$=P)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2=D z2{J1&-eO_^00I0ts6Ds~cwfI|unNo)ntT|^OSD6~@%xoC3#a>;YZ<;eYMlKSA_e!t(l z&%Jl=`#q>@+XMiGcRLe^h^KEp#UMc$$p4`uZ02pn;(&Lw7 zRp?c;UMXW`DGLDTFkrR;vrXv6CZV7)cFO>O4Hq_lJ_W65;q#AQ&~<>q-+gE(!40ix z{r5m}YVA-6s9O$n%NYx>xU!MDaQpe0zAh`DzMK@nq(;jQtI=-YpyZ$i@$63eD*z-j z1=LG9*j>5h19rN=)~-INd++Yb#nU}lRYfvW@Fq!MFOP^1`+$~1FpS=zVr%GoG458E z%oIQr9Ma<A`K|Tk|@8Foy01gSl&jfI;#0ov~U~qpa%(b{s`S!A99@n6AYzkM^gz zpQgnyKsx_++Nf8X*Y6b*`E#U=G>v1%DB}MYdhFFEAGmdb%;eP~2n+@>n5kaM`SOm> zJ)9PMK?b9xyXVZ<>_G^?w^KJ?ToY0@q?Ao|?8)D|JAcH;(E<4R-HHQ1y_Cb*#n-bF uLjE=MmY#?woFg+w<;-l#EZ&&X0N@{6fXWRHD;jtJ0000