OpenSceneGraph-OpenSceneGraph-3.4.1/0000755000175000017500000000000013151044751017062 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/CTestConfig.cmake0000644000175000017500000000105413151044751022234 0ustar albertoalberto## This file should be placed in the root directory of your project. ## Then modify the CMakeLists.txt file in the root directory of your ## project to incorporate the testing dashboard. ## # The following are required to uses Dart and the Cdash dashboard ## ENABLE_TESTING() ## INCLUDE(Dart) set(CTEST_PROJECT_NAME "OpenSceneGraph") set(CTEST_NIGHTLY_START_TIME "00:00:00 CET") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "cdash.openscenegraph.org") set(CTEST_DROP_LOCATION "/submit.php?project=OpenSceneGraph") set(CTEST_DROP_SITE_CDASH TRUE) OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/0000755000175000017500000000000013151044751022477 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/0000755000175000017500000000000013151044751024131 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/0000755000175000017500000000000013151044751025244 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/0000755000175000017500000000000013151044751026033 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg32.xcf0000644000175000017500000000745313151044751027503 0ustar albertoalbertogimp xcf file BB0/ gimp-commentCreated with The GIMP   Pasted Layer     O c s   Ԟ[CtY=% )L60  >AGG(  c025v}V)  l{5Ok  M4?0  C:uc(  \ȴ?:S2+M@  ?XZeMJu>:B 7<:7+   )<5kj?L;;,,2=<0  G=FNB@75 .103G[Y  KO9=B?6k UDK\c/  0eYX5DJ6U +{M]P  GO37U78B sOG  V4B37T76c Na3  *%438_=67 V  z:37Lf@7=A  O3?Z|I9Cc JR5InX;JtZ@iCWdHkqF`Ut|N~^f Q5/A7+ '=;W5" .DyA, %8CD2!$KyW( -H> B).; "6E K1!-ԟ\CvI!)<;S@*0u[?% &5]J&1HGRJC%  JU[DŽVl]7  \+59b7  yµ`qrg  ss|:!  yxc4  _xx17aP   Rkgwhgvxw DVSO5  4UQgvzMKJNVJ5  UMDwxy5 6KMPX[Z  OR;wwv{j TTY_^2  +`VYry{ "pYbR  ;yIsrzzA fXR  Dk1zsrz{ Ia:  $ssqz{zQ  zvss~zz|?  sxzc  Kr}y幙nt }z{y zu|{y~z|Ή G'!6*11M' 9p4*86$=owJ=4 4y.(9 @#|էyj</.H3!lU09SFBA8*:>#>;G*hehė+e8ECDDBw5=DCDDAW}59:=CDDBJ@Yhxkkhԛ-]>3&&1?DD:,070BLB/,=DD>9<- ='NA& #9ADD57 `C2 %5>DD9#7rD?;*/2CDDE5*Yߗ(0CDCH,1:DDNR:5 jD>O"&6CDDRSJ6 @HCH45ADDCDDC?ǘD F>D=DDB癙I JSACDDE𢙚k% IGDDCFo𣘜7Ū裗 Mڜ V.cɖ<II%L4YEנ #U<g  S m  ml0&***"~dba``6yeu*>~  ; b /U Ur!7 white     -   black     '    Background     e y  Selection Mask  'OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg32-32.png0000644000175000017500000000437613151044751027732 0ustar albertoalbertoPNG  IHDR szzbKGDn ]] pHYs  ~tIME =iIDATx{pT?}H!!CP0ѪPTEEg@at,ZDB;Dkh#j<I Iv}޽?Bb9~wL5Ꮆ[D ]Ruj- 4N-%\fF}7N^uɦK.%y#\]s Odz]аe#z |f!x`ӾlGB 0@-=v׊qezo[帺7;]uф^8&MA'kW AgZ[tDH_7VBS$"yZ쨖&BrEϪgZS%HK E^(zn$yi"ƾluF519We)i I t>76z;7zrQIBpĘ3#~dbeOc0p 5r??*iNPN4V{iri"&SώMB 'F[ g-[Y ߨyVvI9X,uO Mwk1 ܷE`X̍\i|{`7fU|Uy ":Hn=ܰ Į=w]7b6$55]E+ Mg8) vDmK;I!ivIK:2GOl% L!?U w@3Bߥ&ff8/LHH4O'} ~| 7Ϗ0p&;ȽZכMs]:DFyIQI+D'LA%d@ҵY})gOD8", (p`TE <\sȊډ =nGhB-q`Ii8@1uP$\45'&EL 3=L݁"!6Ln̸$1`AF( P4%n@BocAH79mLt,: 5f<;rd{\'=ɱb,+sF8PȲ 1RSnHLWLwWRC$料&tI&W `r IHv7sf̘BQQ!u"fdHgҬAS>7ϣ'ˊ>TKIڹ!ylI# q !NKMSeىS% n~7,LS5#&rFPZ-?J\lF _̊hxR$Xްmpo䴬w+ǔ/JgP:iU lQVԩi-i 3n_~~Y38˸gMMm7Lfswaz/'OqIsS8fneu}AG74sʸusѯ⥛yUh$o]̅>|~?~tq,վ ş}Rtn@M-nij4M- b9o|Blq0ڤQY7,ѕoF joq9\o Ky<WY.V7M^(}bZ~de&# K'|$~҇־&=.Z{Étܛ$xnӓ+_~ekY>veYym#k,\OgCIENDB`OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg16.xcf0000644000175000017500000000353313151044751027500 0ustar albertoalbertogimp xcf fileBB0/ gimp-commentCreated with The GIMP Pasted Layer     K_ore._' 3;*  Ї4k] D;2 3FX]=20G*  0CD:P)V[  Zg8?e\'  I~5F85  8DJ@sIRoĿCRkBEfFJUP7+(=y5$#/CC)<ȘE(8S3?se.eøQ.H6 5DҴ5  rƤrc ʲLE !=Ze{FMU,  5HzzO%]\  Pet|Z+  =rzŘ2  u{}sHQn{}{~}~*1p'!85.Ð8*H%1yYjD>(;DD:+α5BDDCoؘJi=BDDCkJ&;DD:7!(M ;DD+'v@'-=DDFXAC;5DDJ" HADDޙ'ِovޜMΛ!pÜ4ՙ"]s2`    Mx>CX white     ,vblack     'L`p Background     ';KOpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg32-8.png0000644000175000017500000000304713151044751027647 0ustar albertoalbertoPNG  IHDR DPLTEƢ>~6z &GZ."3N.J  Fx*6*xn>zB B>zRjBz$.F:J~nf62Jfv2zrJj~fZ^z:vvB"FrVJBBjJ>jf>®ƖࢦZF2rRR2^^JB>R֜*$B6\\(LjVN’~V2jζ0 bBGJN"Bv>zzڶ6vv2Jʖ8*vX>R.LhFΞ2*6Xd22Bldf>N&ҪN*:rr26::BllʺzjR<.2*F2$>>>2N^:rv:N&F:Nb^FڟNJ:zj">J"zrjdb6:VRFN򢚂bz$>. FB44`Nb&>zH~":RNJJҾ¾>zLRFFV2"Zj2΢>JJn:vNZ >J.ƪ&&R檢Ž.226JR.::6BV+60:ZZ6FR&ZZXBz&:rfNVV:6F.6r֞"bbjLNRB4R 3:7O:z ZV*b^.^b.ֲ:>BR&VFRFF6|*:vF^:>V:z>Fz򚔪6(>v*66.tRNS@fbKGDH pHYs  ~tIME+p:PIDATxc`@g1oY/V}ҥng  ce6W!oYx}`_WP ]*R-.j,ޞ"TroҿU%Wz/SbOФG8f,S4X~I|BB%@ҋn'Y@ >8t:{fǁtU zu9[(]"Ԝz1Vw9Pt XWQKJJD< .l`c_1]Q _(pj2#!!urj*lbs٧$-n>#EqL}%w/;nPгBr;bæu^2B"7q$ƫR q    M:4DCC<    8166)59653." N.,5532-! )   Y2#05221,$ ̷U?'"1782.-   WI87378+   aJB?9;7'   gQGC@;6   oZHD><5    Ht_LE?@=  B~эmLHCA3  @f YBBF/   >> ϘoG149  =8L)$ ("   >66=/66=1EC-     ?65:m"?5-    ?649A+ /D?    >779@ 95  .&   ?669=  '& >RW4$-"  ?667;jo  *#%@IGPUY_F(  @6679ho  $7KGKPTVWG9    ?669io  .IMPVLAC<;;%$   ?6579Uo  1RTUO=::AK@336)  ?667>  =QMC=85:JQA5789! A5667=  +PI@:3326;>;776;L&   @7665<  TK?62-++,220044   l:766=  c?;50,(++-,.399:;DB5  =966966:PQ  K8/-*+--*++.02477?DEBEMQD)  * I-*F,*:o3f.'#"%*.H("  .m/(#!/?*#)].'# *7)!  *R1'#  )H*# )j-'#  $A*"  #l.&# "p=*# !V,'#   т2'!  "$%%&(*))(G,&"   ""'-004fppo]Ն0'" "%'*-DLOB+%" "(09oj2&  !%(+0|H,&! &1`{p7&! "$*1K T,&"  !'1V ΂3'!  !%*.^턿C,%"  &1`܏d2Q?)&I& % j6% "#()7wM#:9)" du#  M-'! #+C|e%:OE?    w5&! #&)1?zT?"7HGH?  O+%" #)2^FBCB4BDA@=9) ˁ3(#$&(,Dq\ACHGEC=0-)4#  E,'%'-9ZhD8HNLKH?% +$ <3/5:maQ=9HRSKB<% Пd[LMKNN>   i\XWQPI7    oa^_[SG#  rh^`\UJ    i ug`_ZYP'  m ȇr[]\XF$  qbVXY;  ssɎkQCFH  tuwp5&9  tw~ B.7!  txt^u /I,  tzxej;1P2  t{yq Pc1@C   t{{s >T4/!5"(  s{{t4ER8I <*  s{{v:WX@      t{{v.QH=    s{zxo, EI<@CB@<@:uX/ ,5-:*5@B@==>@BEDB@o)$3qy3(%,/$*4,5BDDBBCDDB D&U"($ $)/5BD D{(8f8..6BDDCDDEDD< /Qm? #%3=>;D D4'"(.cg1!  #)746856>D Dƙn/!"((#146=@>>BD D p6!)/,%1<@BDD n>"#5,-7>BBCD DEjC+)$0=DDCDDE0I+ 4)0>BDD%d g<$*&.=DD}G|U)+/'2=BDDCDD{sH.1'6>EDD{Bgd1)!";2=BDBBDDE D{0{zG'44?JG@BDBBDDE D{ Kl47;:G_R@BDD{ Mc^6*9;CHeS@@ADD{ R]#;;QNN;CA@BDDEDE D~>I8A474E;JG@BDEDEEDDE Du:@7A/7==7=\PEECEDDBn$?=7-6BE=776=?CECDDEBR06*9*27CB@>>@@BBEBDDED$J;7'5;@3?>;87;=>>CADD2=>7,??2=4.?7./27?BDDCD D 5>DB6:9..AHK6-8659?DD M9@DD;5@;15.#*06>51+:CDDE I;BDD>5=:<0 "!*(&26;@D DEJ;BEDB>8-6+"% **+:BCDDEDEDD 4ݒ>BDCDD;*61 ! "030;@EDDEDEEDD @BDD9&9, !**0=D D9DDB56B!   @/.9>BDDCDD 9DEDFB@6O.   *+'5>BBDCCDDM v7DDEFB>7V   16../39>BDD 95BDDCA>0E  $)*0716=ADEDD4w@BDDB@:?     *3@@  Zu{5"(#3-Ezs \   -SbW:AOPUA, (%MzA -i|62Z9 #xO&('[=4 ?޷To}AOW:4 S @94 *ү w:63 q A643 (~ĸ >433 n꩓ ;366 ߔm:6; [ÅB96? ,>76= 3in;66> GШik946> +pzuioͺԻrn_646> P`\VZeryyih_D>436= @ROSVdmrt}ywy}vpb[`quh[U=336>  =PLPW^]^qnpnpusa\WOFIQSS}=336> =GLT^ZXX_d]do[LHJB:>?FLTzp;336=  7HOUPLE8*>hdLGE?><88@M\}W;336> $ ;3GJH;=>53:NtU:427@   >LF47:5.5Jw}L9339I   8IC2578-.Efc>7339] 8EC9442/=G|D=643:_    7@NC710.37Pd&I:633:`  'JRK?434;UmR|7433:` CRNK;9@C`o;@5433:`4/8,$/W,!$)50 ".X, $(0v,#*;*#(2_(!)Q& "(.R"(3  "%.C" 'D}    "',; '%$$"!  "&/^62/+'$  !!%*A QNA,)&$"!! &3e Ӣa7-'#  "%)0p1,($!  #,>ԥZ.&! $)5HЅ5+#  "&*; DA5059iw8+'#  &6g  */#-7(3FOq|B*# "&+M  :=8*$@;4PVUl|:,)&#! "%.W  1)@ZP뾤R;=E[ *KTXcK- 3F7D[a)5 #[uxu9!%6:CVD7DC  Vnxt/!)'70Ex|m}  'GSG(0?EL;)(#Izsyo Satų- (q  dB %$Nĸpr  1ĝEev:D }pr  @߼ oqr  !sЮ prs  eϿ䀚 nrrs !f orss gؑ~ pqrr ʴ|prp  Q۩nnqrp !goqrn )˼äZprro F÷ʰ`qrro /wuzxqerro "\mpkosz|~soX:orsrn %Nfikkty|~}|xqqvpdypssro Lihhnsst~}|~wupjadjlocuossro 'O_dmtpnnpuowrede_\aafidopssrn D[cfa_TA3Lzycbb\]_^^bhgmzpqrro )0"!#HD^ddW\_XXZd{t~{prqqo  L`^ORYTNS^{yhxqssqu     CZXKNRSJHUkSprssq CUVNJMOLGNNu:prtsp   >M^VLJJFHCTa Gqrssp  ,Q]YRJLJJYjMrrssp I\YYMMRN`j6osrssp4/,3"N0*y."O-$l1 &T  G "H&'~   9#    9v .  "V)'" 5񲰬GC5'\͚X-"$w߃d$ 4ΞP"/e!י@ O ?" Lù J"  0 58>5;8mq1&xZO@DC@4+:(4}+. =@@B>:.&?0"Sl-*^ @B@9<6%%*.-$!Gu7B B8D=A5 #- !?s0$ODB;H2@R0)-!#6ώW)&DB>5)'),:'$<z;"&ADB>84/<@( %-?пS6$ 8sD=5$$("++(%%);湜H/3dYcωDA;+EN]0)4563%0DB>;fpK5,DA)H͏DB>9Jn@cl22 DBA9,F򞥵ž ӍDBA@@uƾr DB=4sXy D73LяD7n²ukDC5}` DB1OOB4'MEHBD41yqEEGBD3BvcXHS]insuy}}l?{DBBD40VI7+.>OUT^fptp|{mwl[bw}lAETDE94N?) (17;FFBMTORUGB>4=X^F.9E8ݍD>2.51")/35<83?2&70$!"5351133$!F␙EDD=305-&+3/-04,=?>DA??>.5R> "9gD@6./."#''--'>"( 8B_DA@;524557>;5*2%  >IMDBDBDB9&5& 5Z<΋D:'5$ $X.ЍDCDDCDDCDDCDD;.7!  1P UӐDCDDED D>32/! &GJ D?;,/'*J<%s 663310 . 2+ +((%%#|   !v#$&() + , . /22222222.2222211111111111111111>966:No  ^<0+''+,)+*-*/06?ILLIPX_id5  >9669@p  3D2.+**,++)*-/04GRSRRWcdf`@  >9669=o  M<3..100/*-0315CSYYS]kngY+  >9667:{  3J762635;.19?5=DR]^Xdjh]:  >9667@  OG95376<99=A7AJU]g^ba_B  >86676>  2gWL966=x  YvqP>?6;HPTZ[^_bidb]L  >966<  RtXDFEDJO\`defif\UO  >966:b  DeQMB@N\ccdfgdWXL  ?96659A\   zYQGFMZaaccVS7  W:65566=}    UhVPINX_^`]\YRO$  _<655679a9     lljh[[YPC _;66W  +|olaSRJ' _;667667:M  fxg^YO? a:566=  7mn]Y= |@:7665669@  RkgI!  K<765667:Y  1jsV  x=9667<[  `pX  >97667<_ ,sC   R<97667A9  XV  X@9669>U @V1  @:7656779> '@$    a<765667;Cy    mF976679D=     D:7667:>B  ;%  n=97669>&"v* y@9669AyjwD#-CL:96670@:7679>d=9868>})zJ:779;L%H=977:O,s>967:J,|@:779>t/T:669=u2Q>977=v)@:79=n&\=:9=t2iD99t.k=<>n4K<>v4N>@u1y>A/DF,YPq-dl-|sx{{w}n  gMLKGGIJIKJKINOTY_]XUZ]aie9  sx{{xqo  7QJLIHHJIIJNPOR^c][X[aaedE  sxz{xtn  TMKKNMMLHKORNPX_^ZS\dhj`1  sxz{yvz  7UHKLPNPUKNTZOST\`\T^cdbC  sx{{zyq QMFILPOURORUKSU\]dW\[]H  sw{{|{s  /eYUKUWMQ[Z[X\\]\`^`\Q#  sx{{tx  SnlRISLP[^]a`a_^c]^]O  sx{{u  EtlWMVUTUXabdcbc_ZWS  sx{{v   8aVYRNYaccbcc`U[Q  px{{zxp\   bVYUV[_ddfaaW=  v{||{xt  A\VYX\adfh`^[UR(  u{||{zx8  +bVYZX^gd_\XC1(    u{{zt  z_TTRVW\[QF*    u{{v.  ajUUXVVRVM=   u{{xt   R|mY\YUUYYO;  u{{zvb  /tl^Y_[^a[P1 u{{zys cudgjbba[K  t{{u\  8tcjhc`cQ, u{{xsV  *yfc`ZZS, t{{|{{zw|  em]\^VG v{zz{{xt  5deYYB&  qxyz{{z{{xq Mc`C  vuyz{{yw /fhL txzz{{zu ]gN  rwy{zz{{yu *lA   uxyz{{yx9 U{V  ux{{zxrU @Y3   rvyzz{|zxr +D&     Čuy{|{{zxuy    {xzz{{zxv=     svy{{zwsB  :$  ښtxy{{zxr & "u) qxz{zzxwzkvD#-C}vxzzyt Ȫvjlfsrtxzzyvruyz{zu~uy|{yu|xxzzwr6qvzzxsϒtxzzws/|wyzxt{1wvxzyw~/ܜsxzyw|/rvyzxs~vzzxt}wxyyt3qvyxt)tyxt0xxs8tuws+ђtvs*}us9zsr9rp5mo,t3}ƃ3/=BDDBEDD=BDDB463     (*/AI1>EDD  =BEDD9*L# !$!&045?=5@DD  s9BFDD>4B7    ))$./5:2/;BDD 4>DEDDB=2F)   &)1),'6<)5@DD.=DDB6:V2   $%*(002)/'0=DD;DDCDD=6][F# !$+*,+.3//)0+7@DDj9ADDCD@;4LdH'+00231*&82=BDDGD@BEDDB@;1Fnc1+1//030%.;3>DEDD ~=BDDEDDB>-^rV#  )//1.01/631@DEDD: a7@DDEDDB2Jh,$"(,-/+-38G35CDDC @Z=CDD8=r5&$"+((-40.53=DDC ;DDED94{r6#! !("(37=BDDBDC>T@BDD;0irC% ""-"5BDDCDDBBDDD8@DDB=4`kI,($"$*4*9DDCDDE F;BDDBB>7GgK4(+%(-)372=D DD F@BDDCDB>3^[?:8,,.3<6;@D DEEQ{9@DDB39^B@8-,8BDD9/aW9355<-<@D DBG  i9>DD=0BUF6?<66@BED Dh  A>BDD@93IND5.3=BD Dߜ.  8=>DDB@4:]TB0;@DED D\  A5>BDD;1dXE-9@DD t   B;=BD@9BbN1=DBBDDED 4  ];?B@5`|`-9CEBDDEDED< q7=@=5ZhH6@J@BBDDCDDCDD  A9=>8H_M?@BBDENDDE   4;>:<@@BDDEDDCDDEDDHDR#  !a=;>?CDBABA@BEDDEGD#  ^=;@B@DdN;@DEDDO  L87DK7=>@@?=;`  !z^E<:<;;O_ڟ, @ Ͷ.  ;q  8:  +r!C  t/"  q(G c$c' +! ' -+X 'y+d ].6 X.2 ]/z  Q2= Z1Q#X+#[,QQ4f(\3/[4\"+l))*=74SБ6艿74 4 4 4444444 5 5 5 5 5 5 5 5 5 5 5 5 3 2 //.7+**('&$#   Q"#%&')*+-./A 1 2 4 5 689: 3OJQGJOGZb+>3443:_ #ILOMQRKZ\#=3343:` !KNPPOMYS <33:`  !NMOQNOOMM";339`   ,SPQONPRIJ/b:33:`   !XYVVZQSVMAfA8334;`  Ii`abg]YWP3 =733:a  wyzrone^[G 9e:6233; "wsjdP&'ib84332= wna51C332= tlS !?=33> weC3O:33> %{hU#(>7322332= 4zc)?w94322332= 3sD*>533> (vI{:33>    +svK/A73343>    1^Z>m:623343> mH6433433>  dI94332332> ;r:64332334S #>434337;w  P9332336;X  L943343469>| W;4336;V   v>73343347?g  g>643443349B  -@733467;_    ?74332349F P>733247;_  ]=743347@t 6Z@73347;L[˄>743346=tS;63346:@ N;64336=VF963369>xH95434:Fz=64348=gl=74347@E:4348;G G96337A~'|H7346;K(d=7446= a;646:@ a;636=\(B:679B'@966:E)@769=h*@86:K)>99=M*>9:B~)C:;T.B;@e.a@F-bDd0Nz333  :XS[QUXLY_)psrrsp (QSTRVWNY[%pssrsp %RTUSSRPYT"ossp %SPRQNRROP#psso -TRQONPTLN0pssrp VWUTXOQXODfopssq Cc[]^`WVVT7 oqssq npoife]ZYJ"8prrssp qxrjga_N&'grrssp gzq~rvd]30rqssp ew~scO <psso q~yi]A2upsso {i]N&oqssp "ziY$ =qrssp $}}nd= (osso sqd= qsso   fre@ .nrssrso   ,TP4 prrssrrso   nwrrsstsso   erorssrssro  ;qrtssrssr  #orstssqsp   ~qssrssqrp~   xqrsstsrrqo  Vprssrrssrp    uprsstrssrr  hoqrsrrssrqp  -oqssqrrp   pqrssrsrqu   Qprssrqp  ]nrrsrrqo  4YoqssrqpxYqqrssrrpÿ{prssrrpozprrssro~!rqrssrqo+yqsrsrqp,prrsrsp,Ԗprrsrro,oqssrsps-vqrssrn,uqsrrpw,pqrrp)prrpo.prsrp+nprsqt'oqrrqm/qrrqp/qsrpy/pqqpw0pqpn+rqp0ppq1or-n4r5qDB@-*+!#@6+DC2!,#=4.DE4$3$%51.ÎDE3$5#50BDCDB0%2#"7,NDB=7G0'#''(3(D>3QK10/2'#(3(*萖D;2sSB>;:/+37@DC;3thMI@=895&3rD;,j_HVIL@@'BݎD;-ljNXVIDC"-MΏD;+wmWYQFHD'DD9/{kj\EAD63>ʍD78nlUKM+15SDE77yrWLOE.7OD7,mpTP=.55EDDC5.^^UH-79M񋔙D9B\O<17=5B DED>B<43;=8ߕB DEDB>?@@B;DEDBBA>aDEDEB=I덗DEDB>@񘔙DEDB@;= D@7u DEDB>7Ë DEDDCB>7ō DB@>9SDCDEEDDE@;2󼎖DB@>=;BpċDB@>;8;w Č988<@=ABFYyo锏,!,-,⮏,އ-۔#"  .Ή*΋/ď+Ώ0ϋ0ʋ+Ž1ي2-56q1111111000000000000000/. , + *('%$#! F<"\"%&(( ) , f, 7-023467q==zzwhite     ,ilzziizziiii $ $ $ $==zzblack     'jzzjk zzjjjj&<  $ $ $ $==zz Background     kzzkl4zzklll$ $ $ $ $==zzSelection Masklzzllzzllll $==OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg32-4.png0000644000175000017500000000101513151044751027634 0ustar albertoalbertoPNG  IHDR Tg0PLTEz~#Ew`5&_aB;-BRHF8Gڧ/73xnO*btRNS@fbKGDH pHYs  ~tIME 6K/VIDATxU1K@3hߡ8RApJppp9ŖDťsRP]K,]ACid]"IDb7MxywUH) q˂pVfw0 h01ܽ9_ 8_X"\;$lwbL(_&M*Gʶ_!Oj"7.c(j'dC3C)!!7('D&MCްkjφnSӊi~Ңqעfb_M;ZH~e0R /$R7X(f%KTLޡSIDZ-Nfci#0ZBЖIENDB`OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg48-8.png0000644000175000017500000000410413151044751027651 0ustar albertoalbertoPNG  IHDR00` PLTEΤ6~6z(6Z . 1O 6*.J J F~v*8-Ez  BNwo".fFB6ښ>v\$*1^r*^R$4.">26*ʦ:~Z_^Rnz.ƶzڮfjfNNqv?>ekaC2rv檎sgv7ZV""2FLA2(Bz<^Z*""N/AsHyTJξ򢚪nz6.NN*LO-!B FƓªM[ڲ@2zvvvVB>:AP/Oj* >򪦺"6Rڶ®~z0@-B@vjRfnb>N%'޺Pf&6bVV&ҮX\2ΎR@6>B6^=ƶB¦">€lV澒4$U\(FR:bv"fBޒ?2ބ򲮊F;B3"[SK>z11WrnNʎ~~63AfZR^>bb6*6. 7r¦>8,ھ~:G"ʝQ-Lb"@U:6JzR FFEg%.7tV=?C¿anbZ~.2.4JӜ"FFHnfn8y D[62Fba2Zb*xvnn:8QzJZ.nh@..;Y8BVVlg^FG329+¢ԢBV"::avhܣ.*:LTR^Jl>087b^tRNS@fbKGDH pHYs  ~tIME 'xIDATxS}TSeaRHLaG@?ZEcV'ԥHDfPaj';sc)L^t-ġ| %BncCsϹЂI>LO5"ܙ}"^3S,$3,RI@5=spSiU\mw-+oS_ò9^#2' _$̃e"e<ٲSr5vz/#k/6l|Xqc |o̅7B P(2Wx_J(CL3 U5] +Գ~sEdJ* *Xu:: dQm-=x4;veeuVT0n}g}{A  ۞ط1vAOXlx.x߼`,uCKjZ^>ax0i$BŸH39&]`OKVf¶ĕ1mzhA '۷o艁>HbC@E@ɷz}q -ĒЯ2';H j \lCq֝KBC?[XȜa+eUc56i`WVU+dPXaMހvÃvSxtJ> _2%נ 2LalX)hS%D`˳ӑ}x onłıV+zNG&uc#D#vx8PB.- 8=$W7sфKs '{QEqe:pa;e:fS0j82mZ?ޑVU= sɜHQ;?J.6bכ-E0EYVq hw<2U >D7.få $[^kYm%ʺ‚oһ*ھ$IȔNQ+g wlDǴyp,Rn{YΐLipA %<MaIw#~;"v!~%э;ÚN[[T"7iiiXsn+e$}$BڛM]F<ޖиBqϺٲF',b=مE\7%(rO9#J4t,"cM1O+.;2  $").O<41!"  &IDEKI1.  3U21?6dG "CNI!  3N_fmq`OOS6D>6V9 OI??,  %/( CH<7M5D?6F 6@34:5< C63Bmy4Hn9= @2-,.6:@/$  CA4JBc3Ko:9= :.*++/3KO:6e HR=@MUacC  S\XLV73LQ:6F ^lIObe^9 &{h7z43KYC58D /UM[VC  %^3L33<_F66c VJJ/ 3~.n623<_F66faM>< F7Cz^D9r;>T~pF9[~8DiQ>Yc:N _DZc@`h"kR\cGc%NetX([ŏ]:4K(?Q1! 'Dr%7&"2O"jO-!&Aaf>&!.MyK1! &?CX:$ ")=Ww^I-" !.Oe[D*! *Qf5"%7G\=$ *f܉6! /@Vށ?/ ,kÄTaI#!4H ]3$ $StD->? ;\C" )6g SK-".\n(B5  -+6AeK(#/BF<*9zNHC-+  .YZ\`vC/sywy= DKIJJNW\Y`?  9UTV-sywzN !MLONRT^Za,  2RQR/vsyw{ FXQTZ]_^D  OYUNWrs{w{~ QhUYcc\=  una6rs|{|yC  $X[c\E  {zW1~ssp|{{ qYVW8  &k(mrssp|{{M Rc`[) #n3 ssp|{{ 2f^>   ssp~y{{y UJ {yssvx{{ 3R   nssv}yz{0D! rrs zz|   Lrrt zzމ8I8 !01@srrw}wzӦrs{z{ مru{z|sw|xuw{ysw}yr} {t"w%z(}թR-(?(4F":j%-*%D"`E 6W[2 Bp?"28N-/LmvS<!C\P8Eߥ['*<Q/\ـ(!3Ly2!aȕt݌=(DDB82/ zm7"1i&$/:=BDD>43*-*-`Ѭ)+7ADDEDD??J6A8:JP=)9CDDBjxBHS;~w*-9CDDCBn86G9PCCDDAn˗(g*=DEBDEDEDD? 6/8>AADDE?[yu o8898?DDA@5/DR\c]L`Ce왜ClC:7-+//;BDDC:0#*074#Xޖ1cD@3#"2ADDC;63424 NǗHD@9 &/>CDDCA@AB/" EN KD>1  !)5=DD8) !;PgDA5  2B?DD>*&93 vrDC; &(46ADDA-$>阙.DBD?D)&-.-:DD>=*#+bז1 EDC=O8 /1-3ADD@ZD9.< jDDAc$*-38CDD?cRD?C CBDC;b((8BDCDDCnN8֗E rCC?P9+/6AD D=^>EF @ODCAG04YBCCDEDDCH 2$ /CBBCCEEDCBBo *'ak\A@CMXYf`* #ض򨗗M!  ⣗D,w ћ@SØV"9216 C8󩔥"Q0<%/I[(D۹%2([%N"c% a x "zt5%~ nJ 2 {b  "/&?'?'?%?'?&6u&.u&.u&.u&$u&H& &&&&&u&u&u&u%e"j? , iP((>G+ [} % Eh"-%u(100white     ,f00z00    00black     '<00P00`    00 Background     00+00;    00Selection Mask0000 OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg16-4.png0000644000175000017500000000047213151044751027644 0ustar albertoalbertoPNG  IHDRR0PLTEθB/OvsY^I6(=J5396G htRNS@fbKGDH pHYs  ~tIME<xa\m=x{3,/ځ*[dznKpf6y VGToDj3 %B 'hhsël\Q\rBJp 'ە`Ԅ Qce2sF6w:|=ob\OAK CL͸@f/$?Ȫ4qR:'&ѫ"&v;,(ф kDγTo_?EGH$lH \ c7F/*7ޛ8f/Z-դ}EK,sv۸{d ''U+HZ-jotԬ8T^Wc?p^IgdEU/66 vXuq( UvTMqU5|K;:|x1E3#tMo[O(#AWIENDB`OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg48-4.png0000644000175000017500000000140713151044751027650 0ustar albertoalbertoPNG  IHDR00,0PLTEyz Fw\9,\a4:-ER(9-DD4))R Fᰢ{"tRNS@fbKGDH pHYs  ~tIMEkPIDATxuk`ƅmopH*PR%.;  e pcO;+zb@]acŽ%by7XfV>ŢmnnG+&MiY`YibNj[o4w6FjR{^@?Zi HczNN@CDLȳl8`ҿ>sl krOZ%t8N]IПnt8Yx:%+;A?Xצ ^] FπA a4S-;Hz*YrrH%{tmUZzZ E 2O˘u9xDW]IgK&kK;K#C7tٹksdji&dGn|~&z&i,q !:pL u`WA ѸZ_()K>X Rko$ uQl{(ʻ-z^į2uN S%b"[ӋATs;Hq=憝e'K6B >w ŀa@IENDB`OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/src/osg48-32.png0000644000175000017500000001023613151044751027731 0ustar albertoalbertoPNG  IHDR00WbKGDn ]] pHYs  ~tIME'o댠+IDATxyUŕǿuA7tliHBDA h !~b1hDq .h1c4D'HEEĸYdWuo_5 9nUթ:u >! ]ٖlΟ3zęٹA_dLHIWV?uDΤ3Jy.|]ɤ ʲF8PϨp[_s׃nXB!D'?4M 6g͍qE<Ig?@;LˤC;y{6/_7۷5z5{2 `RM5.aXH9%M5v:B `/k~k8݁UAu4WxhHe/l}PsCr2rU9иuV19@eiiqo.K34w#ݒv*y{g8@!͖#gHLiSG˔  v#6-x)^~ GA+@r_ {v .Odp@~BJ:F[6ᦫ5ȤzZ"Ҩߝ="Gy(ݙ"7)N4 aWhI8&KMQSRJow7ecˑ@@i@$ c$qj>L A*j%ɚ fjݸKb  !U`e4nDm& Q3CAg0(s$d2hAJ*B&G Mqz$)Z[;**m &2)6-3`QhaƣMh4t8c ~fML!Hd%Vή& Rh}AOϜ6gj2I:E( b򦉦Rds!sEb9=7J>VGQmzԆ̬2vܺa(8,{8]aFSH)V@@^HC SU=>"UI D"1dLEU:TWY0u: HJ6m#'c>ܚN(lr ,Ig(F }cO(#*)(:%#3 4䌜ddH8:QIi3ĩlvJJŽhkٮ O9l&*xnӰ3m$w 1+P5mE Ov fc,Kcۖ fSh(R94%IflH>QFЫ0{J%J+xVYxyR 搩Rh/CMA I4b[H$fMc@ٹ;ʴxT"ɐc0cc] L%ٜ=>I7F.Ȣ_@2ͮA`<{B6Վ*TXJu1e #}_8K8"BI 9|3SS95Jn;vYp%Lx=mƳ# 1e?zא,E\p0@"pp+HšLpjw2,ɘY:#[n.f ^L N0!PX)K՛%GTVu@`ZmUX::.H~ϯ]p6; UeX졹;:# ASW\udʚMc,3gNW oPB,䦹^4WR8"J_X{_͵^zyb}T/$.7LWTtz<* ),;SYZC)LREՄ ^})PƖhlJaYFm dŊ/p=ף*D;\HfxyTiՔzc~Pz\nO]T.Q5Os9{39{5ӎH9RUE w/[4)E+kW3Β5{v9h"?dZ[;Xu^x~pxĦ.~7B|~/sԲ+ 9:%lY㫼ЉDE{W=mDU+>< Ϊ G1], }! GG"}D2CQGՄ2~7n׋i>@k(==aTc=k*JnTQ]7>xZ=ODeps? C2ȓv΃nP**~_S'RȖ }VHL >uV}03Bɤwv/«k'.zO٦}Gv.ꌶ.a V7R~V]O"ɪ _N{]˿0wy`s[˕>1k 홶fMKUƑCcEDĺqO_z_+R589k%wmC?Ou>ho=AU+-.4\Vl(70!!1# /"/0nWl&_%""$-"NqVl&b:6""# 2-!!6tVi'f, 2:2 %:?DEEC669uV\'^ DETY\( %OЙi\(SԪp\c*SպV vYD- ѐOp=" FO H湿: #5$0Sǽy}$   2.-:Ӊy}z|Q $ ;ŀyz{x{UF,,%H{xy}xx|ןM]{xz{xx|}zzz|}xxxyƅ}zzxy{xxzzy}|zzzzz}xxxxzxxxxxxxxxyyxxxxxxxxxxzxxxxxxxx|yxxxxzzz}?????( @= =><6;7:-%6$=,:%!+5)43,4532<1:<34:9C EBHAKAMF%@$%K!"B%,T$%W((Z0/A-2\/0O9;`34 J, N1K4S9S='I9z6 z9y:JMR*RU&ZS#ZX*_\3VQfK.`O-fS,a\-o^5`_-^a9^e8deDJO_IMNCTDKP@QU\^^iCBvWV|WXI`^LcmRrcCmtSeyAvthomhgddprn|y{~r5r3u:__|E}Hmnssyw|}@C$K+P+P=^EgKhHiSr[uWv[xa{LMSS_abijoySwmyjx  # /&40>4ABNJVQ]ZdYdeojsktt}Jqfhhuxs|_il}y~}ıȶǸͽ˻˯̳̺ӽĩʱѻp|qmygrf_{ih`v_fea# ]t\n-f$v[_k,,Ic\[_-,jFB[[.dNP94HSGu[-lR3@</~7[},`522;C"D8KZw-%'''1:<42\t.+'''*+ 005ste+*'( ))Dzrh# 64 +>>A==T_oVO_qtY Xv> W? I5̋( 506͍U5  QЈ۪MLbЊ·Ϣ????( ;;=<9 4+&;,*'5&+5/55*9536<3D B D AD CJL@%(Y..G25 M0F1D2+C:&L:IoUx}ael{T O}vjDin,.*_kEfHBgpuhCFA??@IG??(0` %D}[1ʵ/zNIeu[tXQk0R<\cwGΠc-C_E{D8Zct@`hh2}Q1Q}y>6Ycr:}Nư%Vp+"{Fy99[~s8wD⬓i[@^G|Dx9Srñu;w>T~Da,M{>zMk(!{F z8{@Sr5u>f`y*}KPw= z7#HѶar5s8Ps(*Mz<z6'La89kIJ\89A@ CM!"X01Y12f@@stpr5r4wC嬔ni2S,$I z7z6/S||CBB C C E E E D D D C B BoLLvr5r3t;]}Zs,}Ljy=z6{6%KY01>YDDB! CC D E D D D D D D D D C Hqr5r4s5M槐f?ƶ.vK1Sx8{6{6DӽGA G35QRY<D D D D D D D D D D D D D D Cno^s4s3s3v?^ZWn*~K y7{6{6 y8òHC :IU[;JM9C D D D D D D D D D D D D D D A {|yCs4s3s3s7\eF_ |F{6{6{6@bO !D C A24Gfn0^Z4>8<D D D D D C C D D D E D D A?#@§s8s3s3s3p3=E "\s3s3s3p=OS*Y\#UX+NLbWVǪr7s3{L3Tw: z7vrNOD C ;! M= L3 O4 N2R8TA&^Z(Z^4ac6,'A D D D D D D D D D A -2/ROQO$RO>/.v>s3yKPo w:y9̴g==D A5D: K. I* J+ J+ N/W<\MYP2`_B? *93ULTK&VU9-.Is3yKNnH x9z=KD >1N@ N2 K- J, J. Q6T:!T@)Bcs3yKs?uz6FHD @ 9A6W@ P3 N4R:O5&L C D D D D D D C A @ A B /"TC N6 O3TBEcmys4yHڶt>u{61Vc89D @ 3$#bO_IU?U?"?,2 A D D D D D D D C ; 6/%3uz6CdlFGC :7,"-TC+aN/XI/+!; B D D D D D D D C :0B3#fN*s_0xf7zm4q#v`iOiOkSXӾr6zDț.t=u z7oz{8 8;.899 8? D D D D D D D D D A @@95ug/ymDR\c]L`Cew}u;zDț.t=u y8˱ú65,/B08>AAD D D D D D D D D E? [blyuNzEț.(Ly:gjf*%=D0 EB D E D E D D D D D D ? r{Dܽ68Y6ZG=?9 P7"C C D D D D D D D D D D A ndm˼r5s4?;[~w*:3-6)9 C D D D D D D D D D D C Bnsu?r4?Ph=qkZD):*9C D D D D D D D D D D B B'1jxB-5H7;SZgsr6?)gVZ@+8(7A D D D D D D E D D ? ?;@J_i6*4A5:8++:.,JWY[?ً&ZIH1$C./&:= B D D D D D D > 4433ZU*:2-<1*M?-F<`mg?=F 0<*,9pzý$N<H4C1-!1+"> D D D D D B 82.&/YIZD\E `Kzmv7C"/1<ݵiq/HS@K{-".P\Wnh$($*B>/52;B B C C B ? <-$1+"(6)A.1eO@K(#!/8Bb S]2&3$ $GSttuIDCL--a>=g?AHHA 86;3I\Q6C" ))6^gy 2?n!/  ,aktTTa`=I#!(4&! .BMa`jEOc-! &6AWa-7*7&"%2DON4?FQ["1! ':DjrR]%-:(4?K2??????( @ )L7?μ`TBX)$ 1uMPd}xRi# */QTrxPoO.3mJ:{CRq|HЄoM^-&g@f!HhȶJUaT>)"C/%~I{?ʱ{D~IpX;?^Ty>+P˯nn`uLcm&ZS'KA6C C D D D D D D NCTSey_IMSs2q9-Na {8HiLC D&.CmtYN,a\0RQ:C D D D D D D JMRr3s<%}Hb y7smnC @9JKWIWJ*_\-^a30.A D D D D D D A-29^e*RU\^^ѻr5xC.Qe x8Ҽ`34B .7-K2 M0 O3WF#ZX5QP>D D D D D D 9"HDRN4:9w C D D D D D C F%jxddpmyıdL#*-fS)4%7A B D D D D =@QU424563>C@qeV*EJyAQ[ZdJ6=,,#;D D D C 71KAP>"VD[ev|璇 $f,5r .%4gphom?JH=#"T&'V&'DA 8' 2<1RrcCO(,95;-8 GO2#2$2@}˻vWViCBywQ]')?Kk4948Cd*!%3oy3A %'2̘-4"3 '}<+9!!)8LYu~}U`1?$ #1CNe 0 15k-7n#2 )"-_ ?H-,9#  "05=E +(2P /! )7As2%,6-;%3$~D6?(  @,7.!H,Cjn[=X c9};tH,(   GěɮssoHIuQRnnӾ}GJ>+>$X9Lz9ĨG25AD D D D Ҿu8wMx#IAdC;Z\4+&C C D D I:='/`1>훡ysreeY..ie^¿DP.9Њ4 M+ղ-<7E#1e1 &/\&#'sG!.׭(նM"??OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/icons/osg_icon.rc0000644000175000017500000000004513151044751027371 0ustar albertoalbertoOSG_ICON ICON DISCARDABLE "osg.ico" OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/OpenSceneGraphVersionInfo.rc.in0000644000175000017500000000224413151044751032111 0ustar albertoalberto1 VERSIONINFO FILEVERSION ${OPENSCENEGRAPH_MAJOR_VERSION}, ${OPENSCENEGRAPH_MINOR_VERSION}, ${OPENSCENEGRAPH_PATCH_VERSION}, ${OPENSCENEGRAPH_SOVERSION} PRODUCTVERSION ${OPENSCENEGRAPH_MAJOR_VERSION}, ${OPENSCENEGRAPH_MINOR_VERSION}, ${OPENSCENEGRAPH_PATCH_VERSION}, ${OPENSCENEGRAPH_SOVERSION} FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "OpenSceneGraph Binary" VALUE "FileVersion", "${OPENSCENEGRAPH_MAJOR_VERSION}, ${OPENSCENEGRAPH_MINOR_VERSION}, ${OPENSCENEGRAPH_PATCH_VERSION}, ${OPENSCENEGRAPH_SOVERSION}" VALUE "InternalName", "OSG" VALUE "LegalCopyright", "Copyright (C) 2009" VALUE "OriginalFilename", "" VALUE "ProductName", "OpenSceneGraph" VALUE "ProductVersion", "${OPENSCENEGRAPH_MAJOR_VERSION}, ${OPENSCENEGRAPH_MINOR_VERSION}, ${OPENSCENEGRAPH_PATCH_VERSION}, ${OPENSCENEGRAPH_SOVERSION}" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/collect_mangled_names.js0000644000175000017500000000330313151044751030765 0ustar albertoalberto/* collect_mangled_names - Copyright (C) 2006 Joran Jessurun * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. * * Made by Joran Jessurun (A.J.Jessurun@tue.nl) */ var dumpbin="dumpbin"; var fso=WScript.createObject("Scripting.FileSystemObject"); var ForReading=1; var ForWriting=2; var shell=WScript.createObject("WScript.Shell"); function process(file) { WScript.echo("Processing: "+file); var txt=""; var exec=shell.exec(dumpbin+' /linkermember:1 "'+file+'"'); while(!exec.stdOut.atEndOfStream) { var line=exec.stdOut.readLine(); if(/3V\?\$RegisterReaderWriterProxy/.test(line) || /3VRegisterDotOsgWrapperProxy/.test(line)) { txt+=line.substr(10)+"\n"; } } while(exec.status!=1) WScript.sleep(100); if(txt!="") { file=file.replace(/\.lib$/m,".sym"); var f=fso.openTextFile(file,ForWriting,true); f.write(txt); f.close(); WScript.echo("Created: "+file); } } WScript.echo("Collecting mangled names"); var files=new Enumerator(fso.getFolder("..\\lib\\win32").Files); for(;!files.atEnd();files.moveNext()) { if(/_s\.lib$/.test(files.item())) { process(""+files.item()); } } OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/VisualStudio_Syntax_Highlighting.txt0000644000175000017500000000222013151044751033354 0ustar albertoalbertoMapping extensionless header files to C++ in Visual Studio ============================================================================= Previous versions of the OSG included registry files which enabled syntax highlighting for OSG's extensionless headers in Visual Studio. These are not needed anymore, because starting with Visual Studio 2002 (7.0), there is a setting that will map extensionless files to a certain language in the options. This also works for the Express Editions. 1. Go to Tools-Options. 2. Open the Text Editor section, and click on File Extension. 3. At the bottom of the window, check the Map Extensionless Files To checkbox, and select Microsoft Visual C++ in the list to the right. Note that if you use this feature for other languages, you will have to change it when needed. If that is too cumbersome you may want to generate the registry files and do it that way instead. Please see the .reg files in previous versions of OSG in the VisualStudio directory for a guide on how to do that (hint: check the location of the registry key to make sure the added values end up in the right place for your version of Visual Studio). OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/collect_mangled_names.bat0000644000175000017500000000030013151044751031111 0ustar albertoalberto@echo off rem Insert below the path to the installed visual studio vcvars32.bat call "C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat" cscript collect_mangled_names.js OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/osgShell.bat0000644000175000017500000000117413151044751026404 0ustar albertoalberto@echo off REM This script provides a commandline shell properly configured to run OSG REM executables directly from the OpenThreads/OpenSceneGraph source REM trees. REM mew 2004-07-16 cd ..\.. set PATH=%CD%\OpenThreads\bin\win32;%CD%\bin;%CD%\3rdParty\bin;%PATH% set OSG_FILE_PATH=%CD%\OpenSceneGraph-Data;%OSG_FILE_PATH% REM uncomment one of these for your desired notify level... rem set OSG_NOTIFY_LEVEL=ALWAYS rem set OSG_NOTIFY_LEVEL=FATAL rem set OSG_NOTIFY_LEVEL=WARN rem set OSG_NOTIFY_LEVEL=NOTICE rem set OSG_NOTIFY_LEVEL=DEBUG rem set OSG_NOTIFY_LEVEL=DEBUG_FP rem set OSG_NOTIFY_LEVEL=INFO TITLE osgShell %COMSPEC% /K OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Windows/OpenThreadsVersionInfo.rc.in0000644000175000017500000000215613151044751031466 0ustar albertoalberto1 VERSIONINFO FILEVERSION ${OPENTHREADS_MAJOR_VERSION}, ${OPENTHREADS_MINOR_VERSION}, ${OPENTHREADS_PATCH_VERSION}, ${OPENTHREADS_SOVERSION} PRODUCTVERSION ${OPENTHREADS_MAJOR_VERSION}, ${OPENTHREADS_MINOR_VERSION}, ${OPENTHREADS_PATCH_VERSION}, ${OPENTHREADS_SOVERSION} FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "OPENTHREADS Binary" VALUE "FileVersion", "${OPENTHREADS_MAJOR_VERSION}, ${OPENTHREADS_MINOR_VERSION}, ${OPENTHREADS_PATCH_VERSION}, ${OPENTHREADS_SOVERSION}" VALUE "InternalName", "OSG" VALUE "LegalCopyright", "Copyright (C) 2009" VALUE "OriginalFilename", "" VALUE "ProductName", "OPENTHREADS" VALUE "ProductVersion", "${OPENTHREADS_MAJOR_VERSION}, ${OPENTHREADS_MINOR_VERSION}, ${OPENTHREADS_PATCH_VERSION}, ${OPENTHREADS_SOVERSION}" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/0000755000175000017500000000000013151044751024057 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/android.toolchain.cmake0000644000175000017500000024651613151044751030476 0ustar albertoalberto# Copyright (c) 2010-2011, Ethan Rublee # Copyright (c) 2011-2014, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # Android CMake toolchain file, for use with the Android NDK r5-r10c # Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended). # See home page: https://github.com/taka-no-me/android-cmake # # Usage Linux: # $ export ANDROID_NDK=/absolute/path/to/the/android-ndk # $ mkdir build && cd build # $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. # $ make -j8 # # Usage Linux (using standalone toolchain): # $ export ANDROID_STANDALONE_TOOLCHAIN=/absolute/path/to/android-toolchain # $ mkdir build && cd build # $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. # $ make -j8 # # Usage Windows: # You need native port of make to build your project. # Android NDK r7 (and newer) already has make.exe on board. # For older NDK you have to install it separately. # For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm # # $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk # $ mkdir build && cd build # $ cmake.exe -G"MinGW Makefiles" # -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake # -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" .. # $ cmake.exe --build . # # # Options (can be set as cmake parameters: -D=): # ANDROID_NDK=/opt/android-ndk - path to the NDK root. # Can be set as environment variable. Can be set only at first cmake run. # # ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain - path to the # standalone toolchain. This option is not used if full NDK is found # (ignored if ANDROID_NDK is set). # Can be set as environment variable. Can be set only at first cmake run. # # ANDROID_ABI=armeabi-v7a - specifies the target Application Binary # Interface (ABI). This option nearly matches to the APP_ABI variable # used by ndk-build tool from Android NDK. # # Possible targets are: # "armeabi" - ARMv5TE based CPU with software floating point operations # "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions # this ABI target is used by default # "armeabi-v7a with NEON" - same as armeabi-v7a, but # sets NEON as floating-point unit # "armeabi-v7a with VFPV3" - same as armeabi-v7a, but # sets VFPV3 as floating-point unit (has 32 registers instead of 16) # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP # "x86" - IA-32 instruction set # "mips" - MIPS32 instruction set # # 64-bit ABIs for NDK r10 and newer: # "arm64-v8a" - ARMv8 AArch64 instruction set # "x86_64" - Intel64 instruction set (r1) # "mips64" - MIPS64 instruction set (r6) # # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. # Option is read-only when standalone toolchain is used. # Note: building for "android-L" requires explicit configuration. # # ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler # toolchain to be used. The list of possible values depends on the NDK # version. For NDK r10c the possible values are: # # * aarch64-linux-android-4.9 # * aarch64-linux-android-clang3.4 # * aarch64-linux-android-clang3.5 # * arm-linux-androideabi-4.6 # * arm-linux-androideabi-4.8 # * arm-linux-androideabi-4.9 (default) # * arm-linux-androideabi-clang3.4 # * arm-linux-androideabi-clang3.5 # * mips64el-linux-android-4.9 # * mips64el-linux-android-clang3.4 # * mips64el-linux-android-clang3.5 # * mipsel-linux-android-4.6 # * mipsel-linux-android-4.8 # * mipsel-linux-android-4.9 # * mipsel-linux-android-clang3.4 # * mipsel-linux-android-clang3.5 # * x86-4.6 # * x86-4.8 # * x86-4.9 # * x86-clang3.4 # * x86-clang3.5 # * x86_64-4.9 # * x86_64-clang3.4 # * x86_64-clang3.5 # # ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions # instead of Thumb. Is not available for "x86" (inapplicable) and # "armeabi-v6 with VFP" (is forced to be ON) ABIs. # # ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker # errors even if they are not used. # # ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared # libraries. Automatically turned for NDK r5x and r6x due to GLESv2 # problems. # # LIBRARY_OUTPUT_PATH_ROOT=${CMAKE_SOURCE_DIR} - where to output binary # files. See additional details below. # # ANDROID_SET_OBSOLETE_VARIABLES=ON - if set, then toolchain defines some # obsolete variables which were used by previous versions of this file for # backward compatibility. # # ANDROID_STL=gnustl_static - specify the runtime to use. # # Possible values are: # none -> Do not configure the runtime. # system -> Use the default minimal system C++ runtime library. # Implies -fno-rtti -fno-exceptions. # Is not available for standalone toolchain. # system_re -> Use the default minimal system C++ runtime library. # Implies -frtti -fexceptions. # Is not available for standalone toolchain. # gabi++_static -> Use the GAbi++ runtime as a static library. # Implies -frtti -fno-exceptions. # Available for NDK r7 and newer. # Is not available for standalone toolchain. # gabi++_shared -> Use the GAbi++ runtime as a shared library. # Implies -frtti -fno-exceptions. # Available for NDK r7 and newer. # Is not available for standalone toolchain. # stlport_static -> Use the STLport runtime as a static library. # Implies -fno-rtti -fno-exceptions for NDK before r7. # Implies -frtti -fno-exceptions for NDK r7 and newer. # Is not available for standalone toolchain. # stlport_shared -> Use the STLport runtime as a shared library. # Implies -fno-rtti -fno-exceptions for NDK before r7. # Implies -frtti -fno-exceptions for NDK r7 and newer. # Is not available for standalone toolchain. # gnustl_static -> Use the GNU STL as a static library. # Implies -frtti -fexceptions. # gnustl_shared -> Use the GNU STL as a shared library. # Implies -frtti -fno-exceptions. # Available for NDK r7b and newer. # Silently degrades to gnustl_static if not available. # # ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on # chosen runtime. If disabled, then the user is responsible for settings # these options. # # What?: # android-cmake toolchain searches for NDK/toolchain in the following order: # ANDROID_NDK - cmake parameter # ANDROID_NDK - environment variable # ANDROID_STANDALONE_TOOLCHAIN - cmake parameter # ANDROID_STANDALONE_TOOLCHAIN - environment variable # ANDROID_NDK - default locations # ANDROID_STANDALONE_TOOLCHAIN - default locations # # Make sure to do the following in your scripts: # SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) # SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) # The flags will be prepopulated with critical flags, so don't loose them. # Also be aware that toolchain also sets configuration-specific compiler # flags and linker flags. # # ANDROID and BUILD_ANDROID will be set to true, you may test any of these # variables to make necessary Android-specific configuration changes. # # Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64 # will be set true, mutually exclusive. NEON option will be set true # if VFP is set to NEON. # # LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android # libraries will be installed. # Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be # under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME} # (depending on the target ABI). This is convenient for Android packaging. # # ------------------------------------------------------------------------------ # Modified by Lasse Oorni and Yao Wei Tjong for Urho3D cmake_minimum_required( VERSION 2.6.3 ) # Urho3D: on Windows Cygwin-based NDK tools may fail in the linking phase with too long command line. Turn on response files to avoid this if( CMAKE_HOST_WIN32 ) set( CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1 ) set( CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1 ) endif() if( DEFINED CMAKE_CROSSCOMPILING ) # subsequent toolchain loading is not really needed return() endif() if( CMAKE_TOOLCHAIN_FILE ) # touch toolchain variable to suppress "unused variable" warning endif() # inherit settings in recursive loads get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) if( _CMAKE_IN_TRY_COMPILE ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) endif() # this one is important if( CMAKE_VERSION VERSION_GREATER "3.0.99" ) set( CMAKE_SYSTEM_NAME Android ) else() set( CMAKE_SYSTEM_NAME Linux ) endif() # this one not so much set( CMAKE_SYSTEM_VERSION 1 ) # rpath makes low sence for Android set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" ) set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) # NDK search paths set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}/android-ndk" "$ENV{SystemDrive}/NVPACK/android-ndk" ) else() file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) set( ANDROID_NDK_SEARCH_PATHS /opt/android-ndk "${ANDROID_NDK_SEARCH_PATHS}/NVPACK/android-ndk" ) endif() endif() if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH) set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) endif() # known ABIs set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) set( ANDROID_SUPPORTED_ABIS_mips "mips" ) set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" ) # API level defaults # Urho3D: default to API 12 set( ANDROID_DEFAULT_NDK_API_LEVEL 12 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 12) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 12 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 ) macro( __LIST_FILTER listvar regex ) if( ${listvar} ) foreach( __val ${${listvar}} ) if( __val MATCHES "${regex}" ) list( REMOVE_ITEM ${listvar} "${__val}" ) endif() endforeach() endif() endmacro() macro( __INIT_VARIABLE var_name ) set( __test_path 0 ) foreach( __var ${ARGN} ) if( __var STREQUAL "PATH" ) set( __test_path 1 ) break() endif() endforeach() if( __test_path AND NOT EXISTS "${${var_name}}" ) unset( ${var_name} CACHE ) endif() if( "${${var_name}}" STREQUAL "" ) set( __values 0 ) foreach( __var ${ARGN} ) if( __var STREQUAL "VALUES" ) set( __values 1 ) elseif( NOT __var STREQUAL "PATH" ) set( __obsolete 0 ) if( __var MATCHES "^OBSOLETE_.*$" ) string( REPLACE "OBSOLETE_" "" __var "${__var}" ) set( __obsolete 1 ) endif() if( __var MATCHES "^ENV_.*$" ) string( REPLACE "ENV_" "" __var "${__var}" ) set( __value "$ENV{${__var}}" ) elseif( DEFINED ${__var} ) set( __value "${${__var}}" ) else() if( __values ) set( __value "${__var}" ) else() set( __value "" ) endif() endif() if( NOT "${__value}" STREQUAL "" ) if( __test_path ) if( EXISTS "${__value}" ) file( TO_CMAKE_PATH "${__value}" ${var_name} ) if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." ) endif() break() endif() else() set( ${var_name} "${__value}" ) if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." ) endif() break() endif() endif() endif() endforeach() unset( __value ) unset( __values ) unset( __obsolete ) elseif( __test_path ) file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) endif() unset( __test_path ) endmacro() macro( __DETECT_NATIVE_API_LEVEL _var _path ) SET( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" ) FILE( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) if( NOT __apiFileContent ) message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) endif() string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) unset( __apiFileContent ) unset( __ndkApiLevelRegex ) endmacro() macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) if( EXISTS "${_root}" ) file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) __LIST_FILTER( __gccExePath "^[.].*" ) list( LENGTH __gccExePath __gccExePathsCount ) if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "Could not determine machine name for compiler from ${_root}" ) set( ${_var} "" ) else() get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) endif() unset( __gccExePath ) unset( __gccExePathsCount ) unset( __gccExeName ) else() set( ${_var} "" ) endif() endmacro() # fight against cygwin set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") mark_as_advanced( ANDROID_FORBID_SYGWIN ) if( ANDROID_FORBID_SYGWIN ) if( CYGWIN ) message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) endif() if( CMAKE_HOST_WIN32 ) # remove cygwin from PATH set( __new_path "$ENV{PATH}") __LIST_FILTER( __new_path "cygwin" ) set(ENV{PATH} "${__new_path}") unset(__new_path) endif() endif() # detect current host platform if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) mark_as_advanced( ANDROID_NDK_HOST_X64 ) endif() set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) elseif( CMAKE_HOST_WIN32 ) set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) set( TOOL_OS_SUFFIX ".exe" ) elseif( CMAKE_HOST_UNIX ) set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() if( NOT ANDROID_NDK_HOST_X64 ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) endif() # see if we have path to Android NDK __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) if( NOT ANDROID_NDK ) # see if we have path to Android standalone toolchain __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT ) if( NOT ANDROID_STANDALONE_TOOLCHAIN ) #try to find Android NDK in one of the the default locations set( __ndkSearchPaths ) foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) list( APPEND __ndkSearchPaths "${__ndkSearchPath}${suffix}" ) endforeach() endforeach() __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) unset( __ndkSearchPaths ) if( ANDROID_NDK ) message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) else() #try to find Android standalone toolchain in one of the the default locations __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) if( ANDROID_STANDALONE_TOOLCHAIN ) message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) endif( ANDROID_STANDALONE_TOOLCHAIN ) endif( ANDROID_NDK ) endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) endif( NOT ANDROID_NDK ) # remember found paths if( ANDROID_NDK ) get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) set( BUILD_WITH_ANDROID_NDK True ) if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" ) string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) else() set( ANDROID_NDK_RELEASE "r1x" ) set( ANDROID_NDK_RELEASE_FULL "unreleased" ) endif() string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" ) string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum ) math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" ) elseif( ANDROID_STANDALONE_TOOLCHAIN ) get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) # try to detect change if( CMAKE_AR ) string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) endif() unset( __androidStandaloneToolchainPreviousPath ) unset( __length ) endif() set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) else() list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. You should either set an environment variable: export ANDROID_NDK=~/my-android-ndk or export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain or put the toolchain or NDK in the default path: sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH} sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) endif() # android NDK layout if( BUILD_WITH_ANDROID_NDK ) if( NOT DEFINED ANDROID_NDK_LAYOUT ) # try to automatically detect the layout if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") set( ANDROID_NDK_LAYOUT "RELEASE" ) elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) set( ANDROID_NDK_LAYOUT "LINARO" ) elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) set( ANDROID_NDK_LAYOUT "ANDROID" ) endif() endif() set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) mark_as_advanced( ANDROID_NDK_LAYOUT ) if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) endif() get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) # try to detect change of NDK if( CMAKE_AR ) string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. " ) endif() unset( __androidNdkPreviousPath ) unset( __length ) endif() endif() # get all the details about standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) set( __availableToolchains "standalone" ) __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) if( NOT __availableToolchainMachines ) message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) endif() if( __availableToolchainMachines MATCHES x86_64 ) set( __availableToolchainArchs "x86_64" ) elseif( __availableToolchainMachines MATCHES i686 ) set( __availableToolchainArchs "x86" ) elseif( __availableToolchainMachines MATCHES aarch64 ) set( __availableToolchainArchs "arm64" ) elseif( __availableToolchainMachines MATCHES arm ) set( __availableToolchainArchs "arm" ) elseif( __availableToolchainMachines MATCHES mips64el ) set( __availableToolchainArchs "mips64" ) elseif( __availableToolchainMachines MATCHES mipsel ) set( __availableToolchainArchs "mips" ) endif() execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) list( APPEND __availableToolchains "standalone-clang" ) list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) endif() endif() macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) foreach( __toolchain ${${__availableToolchainsLst}} ) if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" ) FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" ) if( __toolchainVersionStr ) string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" ) string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" ) else() string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) endif() unset( __toolchainVersionStr ) unset( __toolchainVersionRegex ) else() set( __gcc_toolchain "${__toolchain}" ) endif() __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) if( __machine ) string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) if( __machine MATCHES x86_64 ) set( __arch "x86_64" ) elseif( __machine MATCHES i686 ) set( __arch "x86" ) elseif( __machine MATCHES aarch64 ) set( __arch "arm64" ) elseif( __machine MATCHES arm ) set( __arch "arm" ) elseif( __machine MATCHES mips64el ) set( __arch "mips64" ) elseif( __machine MATCHES mipsel ) set( __arch "mips" ) else() set( __arch "" ) endif() #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n") if (__arch) list( APPEND __availableToolchainMachines "${__machine}" ) list( APPEND __availableToolchainArchs "${__arch}" ) list( APPEND __availableToolchainCompilerVersions "${__version}" ) list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) endif() endif() unset( __gcc_toolchain ) endforeach() endmacro() # get all the details about NDK if( BUILD_WITH_ANDROID_NDK ) file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) set( __availableToolchains "" ) set( __availableToolchainMachines "" ) set( __availableToolchainArchs "" ) set( __availableToolchainCompilerVersions "" ) if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) # do not go through all toolchains if we know the name set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) if( __availableToolchains ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) endif() endif() endif() if( NOT __availableToolchains ) file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) if( __availableToolchains ) list(SORT __availableToolchainsLst) # we need clang to go after gcc endif() __LIST_FILTER( __availableToolchainsLst "^[.]" ) __LIST_FILTER( __availableToolchainsLst "llvm" ) __LIST_FILTER( __availableToolchainsLst "renderscript" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) if( __availableToolchains ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) endif() endif() endif() if( NOT __availableToolchains ) message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) endif() endif() # build list of available ABIs set( ANDROID_SUPPORTED_ABIS "" ) set( __uniqToolchainArchNames ${__availableToolchainArchs} ) list( REMOVE_DUPLICATES __uniqToolchainArchNames ) list( SORT __uniqToolchainArchNames ) foreach( __arch ${__uniqToolchainArchNames} ) list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) endforeach() unset( __uniqToolchainArchNames ) if( NOT ANDROID_SUPPORTED_ABIS ) message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) endif() # choose target ABI __INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} ) # verify that target ABI is supported list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) if( __androidAbiIdx EQUAL -1 ) string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" " ) endif() unset( __androidAbiIdx ) # set target ABI options if( ANDROID_ABI STREQUAL "x86" ) set( X86 true ) set( ANDROID_NDK_ABI_NAME "x86" ) set( ANDROID_ARCH_NAME "x86" ) set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "i686" ) elseif( ANDROID_ABI STREQUAL "x86_64" ) set( X86 true ) set( X86_64 true ) set( ANDROID_NDK_ABI_NAME "x86_64" ) set( ANDROID_ARCH_NAME "x86_64" ) set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) elseif( ANDROID_ABI STREQUAL "mips64" ) set( MIPS64 true ) set( ANDROID_NDK_ABI_NAME "mips64" ) set( ANDROID_ARCH_NAME "mips64" ) set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips64" ) elseif( ANDROID_ABI STREQUAL "mips" ) set( MIPS true ) set( ANDROID_NDK_ABI_NAME "mips" ) set( ANDROID_ARCH_NAME "mips" ) set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips" ) elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) set( ARM64_V8A true ) set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) set( ANDROID_ARCH_NAME "arm64" ) set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) set( VFPV3 true ) set( NEON true ) elseif( ANDROID_ABI STREQUAL "armeabi" ) set( ARMEABI true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) set( ARMEABI_V6 true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv6" ) # need always fallback to older platform set( ARMEABI true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a") set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) set( NEON true ) else() message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) endif() if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) # really dirty hack # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) endif() if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD OBSOLETE_FORCE_ARM VALUES OFF ) set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) else() unset( ANDROID_FORCE_ARM_BUILD CACHE ) endif() # choose toolchain if( ANDROID_TOOLCHAIN_NAME ) list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) if( __toolchainIdx EQUAL -1 ) list( SORT __availableToolchains ) string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) set( toolchains_list " * ${toolchains_list}") message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) endif() list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME ) message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) endif() else() set( __toolchainIdx -1 ) set( __applicableToolchains "" ) set( __toolchainMaxVersion "0.0.0" ) list( LENGTH __availableToolchains __availableToolchainsCount ) math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) foreach( __idx RANGE ${__availableToolchainsCount} ) list( GET __availableToolchainArchs ${__idx} __toolchainArch ) if( __toolchainArch STREQUAL ANDROID_ARCH_NAME ) list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) set( __toolchainMaxVersion "${__toolchainVersion}" ) set( __toolchainIdx ${__idx} ) endif() endif() endforeach() unset( __availableToolchainsCount ) unset( __toolchainMaxVersion ) unset( __toolchainVersion ) endif() unset( __toolchainArch ) if( __toolchainIdx EQUAL -1 ) message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) endif() list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) unset( __toolchainIdx ) unset( __availableToolchains ) unset( __availableToolchainMachines ) unset( __availableToolchainArchs ) unset( __availableToolchainCompilerVersions ) # choose native API level __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL ) # adjust API level set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level ) set( __real_api_level ${__level} ) endif() endforeach() if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level ) message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) endif() unset(__real_api_level) # validate list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) if( __levelIdx EQUAL -1 ) message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) else() if( BUILD_WITH_ANDROID_NDK ) __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 ) message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) endif() unset( __realApiLevel ) endif() set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) if( CMAKE_VERSION VERSION_GREATER "2.8" ) list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) endif() endif() unset( __levelIdx ) # remember target ABI set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) if( CMAKE_VERSION VERSION_GREATER "2.8" ) list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} ) set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} ) endif() # runtime choice (STL, rtti, exceptions) if( NOT ANDROID_STL ) # honor legacy ANDROID_USE_STLPORT if( DEFINED ANDROID_USE_STLPORT ) if( ANDROID_USE_STLPORT ) set( ANDROID_STL stlport_static ) endif() message( WARNING "You are using an obsolete variable ANDROID_USE_STLPORT to select the STL variant. Use -DANDROID_STL=stlport_static instead." ) endif() if( NOT ANDROID_STL ) set( ANDROID_STL gnustl_static ) endif() endif() set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) if( BUILD_WITH_ANDROID_NDK ) if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$") message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". The possible values are: none -> Do not configure the runtime. system -> Use the default minimal system C++ runtime library. system_re -> Same as system but with rtti and exceptions. gabi++_static -> Use the GAbi++ runtime as a static library. gabi++_shared -> Use the GAbi++ runtime as a shared library. stlport_static -> Use the STLport runtime as a static library. stlport_shared -> Use the STLport runtime as a shared library. gnustl_static -> (default) Use the GNU STL as a static library. gnustl_shared -> Use the GNU STL as a shared library. " ) endif() elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". The possible values are: none -> Do not configure the runtime. gnustl_static -> (default) Use the GNU STL as a static library. gnustl_shared -> Use the GNU STL as a shared library. " ) endif() endif() unset( ANDROID_RTTI ) unset( ANDROID_EXCEPTIONS ) unset( ANDROID_STL_INCLUDE_DIRS ) unset( __libstl ) unset( __libsupcxx ) if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). You are strongly recommended to switch to another NDK release. " ) endif() if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h index 5e28c64..65892a1 100644 --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h @@ -51,7 +51,11 @@ typedef long int ssize_t; #endif #ifndef _PTRDIFF_T #define _PTRDIFF_T -typedef long ptrdiff_t; +# ifdef __ANDROID__ + typedef int ptrdiff_t; +# else + typedef long ptrdiff_t; +# endif #endif " ) endif() # setup paths and STL for standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) # old location ( pre r8c ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) else() list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) endif() # always search static GNU STL to get the location of libsupc++.a if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) endif() if( __libstl ) set( __libsupcxx "${__libstl}/libsupc++.a" ) set( __libstl "${__libstl}/libstdc++.a" ) endif() if( NOT EXISTS "${__libsupcxx}" ) message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. You need to either upgrade to newer NDK or manually copy $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a to ${__libsupcxx} " ) endif() if( ANDROID_STL STREQUAL "gnustl_shared" ) if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) endif() endif() endif() endif() # clang if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) set( ANDROID_COMPILER_IS_CLANG 1 ) execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) message( FATAL_ERROR "Could not find the Clang compiler driver" ) endif() set( ANDROID_COMPILER_IS_CLANG 1 ) set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) else() set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) unset( ANDROID_COMPILER_IS_CLANG CACHE ) endif() string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) set( _clang_name "clang" ) endif() # setup paths and STL for NDK if( BUILD_WITH_ANDROID_NDK ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) if( ANDROID_STL STREQUAL "none" ) # do nothing elseif( ANDROID_STL STREQUAL "system" ) set( ANDROID_RTTI OFF ) set( ANDROID_EXCEPTIONS OFF ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) elseif( ANDROID_STL STREQUAL "system_re" ) set( ANDROID_RTTI ON ) set( ANDROID_EXCEPTIONS ON ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) elseif( ANDROID_STL MATCHES "gabi" ) if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 message( FATAL_ERROR "gabi++ is not awailable in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") endif() set( ANDROID_RTTI ON ) set( ANDROID_EXCEPTIONS OFF ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) elseif( ANDROID_STL MATCHES "stlport" ) if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d set( ANDROID_EXCEPTIONS ON ) else() set( ANDROID_EXCEPTIONS OFF ) endif() if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 set( ANDROID_RTTI OFF ) else() set( ANDROID_RTTI ON ) endif() set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) elseif( ANDROID_STL MATCHES "gnustl" ) set( ANDROID_EXCEPTIONS ON ) set( ANDROID_RTTI ON ) if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) # gnustl binary for 4.7 compiler is buggy :( # TODO: look for right fix set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) else() set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) endif() else() set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) endif() set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" ) if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) else() set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) endif() else() message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) endif() # find libsupc++.a - rtti & exceptions if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer if( NOT EXISTS "${__libsupcxx}" ) set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 endif() if( NOT EXISTS "${__libsupcxx}" ) # before r7 if( ARMEABI_V7A ) if( ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) else() set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) endif() elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) else() set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) endif() endif() if( NOT EXISTS "${__libsupcxx}") message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") endif() endif() endif() # case of shared STL linkage if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) # TODO: check if .so file exists before the renaming endif() # ccache support __INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) if( _ndk_ccache ) if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) unset( NDK_CCACHE CACHE ) endif() find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") else() unset( NDK_CCACHE CACHE ) endif() unset( _ndk_ccache ) # setup the cross-compiler if( NOT CMAKE_C_COMPILER ) if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") else() set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") endif() else() if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") else() set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) endif() endif() set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) endif() set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) if( CMAKE_VERSION VERSION_LESS 2.8.5 ) set( CMAKE_ASM_COMPILER_ARG1 "-c" ) endif() if( APPLE ) find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) if( NOT CMAKE_INSTALL_NAME_TOOL ) message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) endif() mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) endif() # Force set compilers because standard identification works badly for us include( CMakeForceCompiler ) CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ID Clang) endif() set( CMAKE_C_PLATFORM_ID Linux ) if( X86_64 OR MIPS64 OR ARM64_V8A ) set( CMAKE_C_SIZEOF_DATA_PTR 8 ) else() set( CMAKE_C_SIZEOF_DATA_PTR 4 ) endif() set( CMAKE_C_HAS_ISYSROOT 1 ) set( CMAKE_C_COMPILER_ABI ELF ) CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_CXX_COMPILER_ID Clang) endif() set( CMAKE_CXX_PLATFORM_ID Linux ) set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} ) set( CMAKE_CXX_HAS_ISYSROOT 1 ) set( CMAKE_CXX_COMPILER_ABI ELF ) set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) # force ASM compiler (required for CMake < 2.8.5) set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) set( CMAKE_ASM_COMPILER_ID GNU ) set( CMAKE_ASM_COMPILER_WORKS TRUE ) set( CMAKE_ASM_COMPILER_FORCED TRUE ) set( CMAKE_COMPILER_IS_GNUASM 1) set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) # flags and definitions remove_definitions( -DANDROID ) add_definitions( -DANDROID ) if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) if( CMAKE_HOST_WIN32 ) # try to convert path to 8.3 form file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE __result ERROR_QUIET ) if( __result EQUAL 0 ) file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) else() set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) endif() else() set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) endif() if( NOT _CMAKE_IN_TRY_COMPILE ) # quotes can break try_compile and compiler identification message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") endif() else() set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) endif() # NDK flags if (ARM64_V8A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -ffunction-sections -funwind-tables" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) endif() elseif( ARMEABI OR ARMEABI_V7A) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" ) if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) endif() else() # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) endif() endif() elseif( X86 OR X86_64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" ) endif() set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) elseif( MIPS OR MIPS64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) endif() elseif() set( ANDROID_CXX_FLAGS_RELEASE "" ) set( ANDROID_CXX_FLAGS_DEBUG "" ) endif() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) endif() if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ endif() # ABI-specific flags if( ARMEABI_V7A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) if( NEON ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) elseif( VFPV3 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) endif() elseif( ARMEABI_V6 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 elseif( ARMEABI ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) endif() if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) else() set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) endif() # STL if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) if( EXISTS "${__libstl}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) endif() if( EXISTS "${__libsupcxx}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) # C objects: set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) set( CMAKE_C_LINK_EXECUTABLE " -o " ) set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) endif() if( ANDROID_STL MATCHES "gnustl" ) if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) set( ANDROID_LIBM_PATH -lm ) endif() set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) endif() endif() # variables controlling optional build flags if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. # So this flag option is required for all projects using OpenGL from native. __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) else() __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) endif() __INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON ) __INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) __INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) __INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) __INIT_VARIABLE( ANDROID_RELRO VALUES ON ) set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" ) set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) # linker flags set( ANDROID_LINKER_FLAGS "" ) if( ARMEABI_V7A ) # this is *required* to use the following linker flags that routes around # a CPU bug in some Cortex-A8 implementations: set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) endif() if( ANDROID_NO_UNDEFINED ) if( MIPS ) # there is some sysroot-related problem in mips linker... if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) endif() else() set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) endif() endif() if( ANDROID_SO_UNDEFINED ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) endif() if( ANDROID_FUNCTION_LEVEL_LINKING ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) endif() if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 On Linux and OS X host platform you can workaround this problem using gold linker (default). Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. " ) endif() endif() # version 4.6 if( ANDROID_NOEXECSTACK ) if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) endif() set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) endif() if( ANDROID_RELRO ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) endif() if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" ) if( BUILD_WITH_ANDROID_NDK ) set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) endif() endif() # cache flags set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) # Urho3D: optimise for size set( CMAKE_CXX_FLAGS_RELEASE "-Os -DNDEBUG" CACHE STRING "c++ Release flags" ) set( CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG" CACHE STRING "c Release flags" ) set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) # put flags to cache (for debug purpose only) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) # finish flags set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) endif() # configure rtti if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) if( ANDROID_RTTI ) set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) endif() endif() # configure exceptios if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) if( ANDROID_EXCEPTIONS ) set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) endif() endif() # global includes and link directories include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning link_directories( "${__android_install_path}" ) # detect if need link crtbegin_so.o explicitly if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) string( REPLACE "" "-shared" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) separate_arguments( __cmd ) foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) if( ${__var} ) set( __tmp "${${__var}}" ) separate_arguments( __tmp ) string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") endif() endforeach() string( REPLACE "'" "" __cmd "${__cmd}" ) string( REPLACE "\"" "" __cmd "${__cmd}" ) execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) if( __cmd_result EQUAL 0 ) set( ANDROID_EXPLICIT_CRT_LINK ON ) else() set( ANDROID_EXPLICIT_CRT_LINK OFF ) endif() endif() if( ANDROID_EXPLICIT_CRT_LINK ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) endif() # setup output directories set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" ) set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) if(NOT _CMAKE_IN_TRY_COMPILE) if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) else() set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) endif() # Urho3D: All libraries are first generated in CMake default binary directory and only the main target library is later copied to below output path by Urho3D own build script set( ANDROID_LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" FORCE ) endif() # copy shaed stl library to build directory if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) get_filename_component( __libstlname "${__libstl}" NAME ) execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) endif() unset( __fileCopyProcess ) unset( __libstlname ) endif() # set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) # where is the target environment set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) # only search for libraries and includes in the ndk toolchain set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) # macro to find packages on the host OS macro( find_host_package ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_package( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # macro to find programs on the host OS macro( find_host_program ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_program( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR ) if( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI" ) set( ${VAR} "armeabi" ) elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" ) set( ${VAR} "armeabi-v7a" ) elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" ) set( ${VAR} "x86" ) elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS" ) set( ${VAR} "mips" ) else() set( ${VAR} "unknown" ) endif() endmacro() # export toolchain settings for the try_compile() command if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) set( __toolchain_config "") foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES ANDROID_NDK_HOST_X64 ANDROID_NDK ANDROID_NDK_LAYOUT ANDROID_STANDALONE_TOOLCHAIN ANDROID_TOOLCHAIN_NAME ANDROID_ABI ANDROID_NATIVE_API_LEVEL ANDROID_STL ANDROID_STL_FORCE_FEATURES ANDROID_FORCE_ARM_BUILD ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ANDROID_LIBM_PATH ANDROID_EXPLICIT_CRT_LINK ) if( DEFINED ${__var} ) if( "${__var}" MATCHES " ") set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) else() set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) endif() endif() endforeach() file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) unset( __toolchain_config ) endif() # force cmake to produce / instead of \ in build commands for Ninja generator if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) # it is a bad hack after all # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion enable_language( C ) enable_language( CXX ) # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it unset( MINGW ) endif() # set some obsolete variables for backward compatibility set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" ) mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES ) if( ANDROID_SET_OBSOLETE_VARIABLES ) set( ANDROID_API_LEVEL ${ANDROID_NATIVE_API_LEVEL} ) set( ARM_TARGET "${ANDROID_ABI}" ) set( ARMEABI_NDK_NAME "${ANDROID_NDK_ABI_NAME}" ) endif() # Variables controlling behavior or set by cmake toolchain: # ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64" # ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version) # ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none # ANDROID_FORBID_SYGWIN : ON/OFF # ANDROID_NO_UNDEFINED : ON/OFF # ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) # ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF # ANDROID_GOLD_LINKER : ON/OFF # ANDROID_NOEXECSTACK : ON/OFF # ANDROID_RELRO : ON/OFF # ANDROID_FORCE_ARM_BUILD : ON/OFF # ANDROID_STL_FORCE_FEATURES : ON/OFF # ANDROID_SET_OBSOLETE_VARIABLES : ON/OFF # Can be set only at the first run: # ANDROID_NDK # ANDROID_STANDALONE_TOOLCHAIN # ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain # ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) # ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) # LIBRARY_OUTPUT_PATH_ROOT : # NDK_CCACHE : # Obsolete: # ANDROID_API_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL # ARM_TARGET : superseded by ANDROID_ABI # ARM_TARGETS : superseded by ANDROID_ABI (can be set only) # ANDROID_NDK_TOOLCHAIN_ROOT : superseded by ANDROID_STANDALONE_TOOLCHAIN (can be set only) # ANDROID_USE_STLPORT : superseded by ANDROID_STL=stlport_static # ANDROID_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL (completely removed) # # Primary read-only variables: # ANDROID : always TRUE # ARMEABI : TRUE for arm v6 and older devices # ARMEABI_V6 : TRUE for arm v6 # ARMEABI_V7A : TRUE for arm v7a # ARM64_V8A : TRUE for arm64-v8a # NEON : TRUE if NEON unit is enabled # VFPV3 : TRUE if VFP version 3 is enabled # X86 : TRUE if configured for x86 # X86_64 : TRUE if configured for x86_64 # MIPS : TRUE if configured for mips # MIPS64 : TRUE if configured for mips64 # BUILD_ANDROID : always TRUE # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI # ANDROID_NDK_RELEASE : from r5 to r10c; set only for NDK # ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor) # ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI # ANDROID_SYSROOT : path to the compiler sysroot # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform # ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used # Obsolete: # ARMEABI_NDK_NAME : superseded by ANDROID_NDK_ABI_NAME # # Secondary (less stable) read-only variables: # ANDROID_COMPILER_VERSION : GCC version used (not Clang version) # ANDROID_CLANG_VERSION : version of clang compiler if clang is used # ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform # ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI # ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" # ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) # ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools # ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK # ANDROID_STL_INCLUDE_DIRS : stl include paths # ANDROID_RTTI : if rtti is enabled by the runtime # ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime # ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used # ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` # # Defaults: # ANDROID_DEFAULT_NDK_API_LEVEL # ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} # ANDROID_NDK_SEARCH_PATHS # ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH # ANDROID_SUPPORTED_ABIS_${ARCH} # ANDROID_SUPPORTED_NDK_VERSIONS OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/Application.mk.master.in0000644000175000017500000000064513151044751030557 0ustar albertoalberto#ANDROID APPLICATION MAKEFILE APP_BUILD_SCRIPT := $(call my-dir)/Android.mk APP_PROJECT_PATH := $(call my-dir) APP_OPTIM := ${ANDROID_RELEASE_OPTIM} APP_PLATFORM := android-${ANDROID_PLATFORM} APP_STL := ${ANDROID_STL} APP_CPPFLAGS := -fexceptions -frtti #APP_CPPFLAGS := -Os -mthumb-interwork -fno-short-enums #APP_CPPFLAGS := -Wl,--no-undefined APP_ABI := ${ANDROID_ABI} APP_MODULES := $ENV{AND_OSG_LIB_NAMES} OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/AndroidManifest.xml.master.in0000644000175000017500000000041313151044751031545 0ustar albertoalberto OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/Android.mk.src.in0000644000175000017500000000020613151044751027161 0ustar albertoalberto#ANDROID makefile in src SRC_ROOT := $(call my-dir) LOCAL_PATH := $(call my-dir) SRC_ROOT := $(LOCAL_PATH) $ENV{AND_OSG_LIB_PATHS} OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/Android.mk.serializers.in0000644000175000017500000000117513151044751030734 0ustar albertoalberto#ANDROID makefile in src SERIALIZER_ROOT := $(call my-dir) LOCAL_PATH := $(call my-dir) SERIALIZER_ROOT := $(LOCAL_PATH) #include $(call all-subdir-makefiles) include $(SERIALIZER_ROOT)/osg/Android.mk include $(SERIALIZER_ROOT)/osgAnimation/Android.mk include $(SERIALIZER_ROOT)/osgFX/Android.mk include $(SERIALIZER_ROOT)/osgManipulator/Android.mk include $(SERIALIZER_ROOT)/osgParticle/Android.mk include $(SERIALIZER_ROOT)/osgShadow/Android.mk include $(SERIALIZER_ROOT)/osgSim/Android.mk include $(SERIALIZER_ROOT)/osgTerrain/Android.mk include $(SERIALIZER_ROOT)/osgText/Android.mk include $(SERIALIZER_ROOT)/osgVolume/Android.mk OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/Android.mk.master.in0000644000175000017500000000033313151044751027666 0ustar albertoalberto#ANDROID ROOT MAKEFILE OSG_ROOT := $(call my-dir) LOCAL_PATH := $(call my-dir) OSG_ROOT := $(LOCAL_PATH) OSGInclude := $(OSG_ROOT)/include/OpenThreads \ $(OSG_ROOT)/include/osg include src/Android.mk OpenSceneGraph-OpenSceneGraph-3.4.1/PlatformSpecifics/Android/Android.mk.modules.in0000644000175000017500000000134713151044751030051 0ustar albertoalberto#ANDROID makefile ${MODULE_NAME} LOCAL_PATH := ${MODULE_DIR} include $(CLEAR_VARS) ifeq (${ANDROID_OPTIM_NEON},true) ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_ARM_NEON := true endif endif ifeq (${ANDROID_OPTIM_ARM32},true) LOCAL_ARM_MODE := arm endif LOCAL_CPP_EXTENSION := ${CPP_EXTENSION} LOCAL_LDLIBS := ${MODULE_LIBS_FLAGS} LOCAL_MODULE := ${MODULE_NAME} LOCAL_SRC_FILES := ${MODULE_SOURCES} LOCAL_C_INCLUDES := ${MODULE_INCLUDES} LOCAL_CFLAGS := ${MODULE_FLAGS_C} LOCAL_CPPFLAGS := ${MODULE_FLAGS_CPP} LOCAL_SHARED_LIBRARIES := ${MODULE_LIBS_SHARED} LOCAL_STATIC_LIBRARIES := ${MODULE_LIBS_STATIC} include ${MODULE_BUILD_TYPE} OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/0000755000175000017500000000000013151044751021373 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/Find3rdPartyDependencies.cmake0000644000175000017500000001625313151044751027224 0ustar albertoalberto################################################################################################ # this Macro find a generic dependency, handling debug suffix # all the paramenter are required, in case of lists, use "" in calling ################################################################################################ MACRO(FIND_DEPENDENCY DEPNAME INCLUDEFILE LIBRARY_NAMES_BASE SEARCHPATHLIST DEBUGSUFFIX EXSUFFIX) MESSAGE(STATUS "searching ${DEPNAME} -->${INCLUDEFILE}<-->${LIBRARY_NAMES_BASE}<-->${SEARCHPATHLIST}<--") SET(MY_PATH_INCLUDE ) SET(MY_PATH_LIB ) FOREACH( MYPATH ${SEARCHPATHLIST} ) SET(MY_PATH_INCLUDE ${MY_PATH_INCLUDE} ${MYPATH}/include) SET(MY_PATH_LIB ${MY_PATH_LIB} ${MYPATH}/lib) ENDFOREACH( MYPATH ${SEARCHPATHLIST} ) FIND_PATH("${DEPNAME}_INCLUDE_DIR" ${INCLUDEFILE} ${MY_PATH_INCLUDE} NO_DEFAULT_PATH ) MARK_AS_ADVANCED("${DEPNAME}_INCLUDE_DIR") #MESSAGE( " ${DEPNAME}_INCLUDE_DIR --> ${${DEPNAME}_INCLUDE_DIR}<--") SET(LIBRARY_NAMES "") FOREACH(LIBNAME ${LIBRARY_NAMES_BASE}) LIST(APPEND LIBRARY_NAMES "${LIBNAME}${EXSUFFIX}") ENDFOREACH(LIBNAME) FIND_LIBRARY("${DEPNAME}_LIBRARY" NAMES ${LIBRARY_NAMES} PATHS ${MY_PATH_LIB} NO_DEFAULT_PATH ) SET(LIBRARY_NAMES_DEBUG "") FOREACH(LIBNAME ${LIBRARY_NAMES_BASE}) LIST(APPEND LIBRARY_NAMES_DEBUG "${LIBNAME}${DEBUGSUFFIX}${EXSUFFIX}") ENDFOREACH(LIBNAME) FIND_LIBRARY("${DEPNAME}_LIBRARY_DEBUG" NAMES ${LIBRARY_NAMES_DEBUG} PATHS ${MY_PATH_LIB} NO_DEFAULT_PATH ) MARK_AS_ADVANCED("${DEPNAME}_LIBRARY") #MESSAGE( " ${DEPNAME}_LIBRARY --> ${${DEPNAME}_LIBRARY}<--") SET( ${DEPNAME}_FOUND "NO" ) IF(${DEPNAME}_INCLUDE_DIR AND ${DEPNAME}_LIBRARY) SET( ${DEPNAME}_FOUND "YES" ) IF(NOT ${DEPNAME}_LIBRARY_DEBUG) MESSAGE("-- Warning Debug ${DEPNAME} not found, using: ${${DEPNAME}_LIBRARY}") SET(${DEPNAME}_LIBRARY_DEBUG "${${DEPNAME}_LIBRARY}") ENDIF(NOT ${DEPNAME}_LIBRARY_DEBUG) SET(${DEPNAME}_LIBRARIES debug ${${DEPNAME}_LIBRARY_DEBUG} optimized ${${DEPNAME}_LIBRARY} ) ENDIF(${DEPNAME}_INCLUDE_DIR AND ${DEPNAME}_LIBRARY) ENDMACRO(FIND_DEPENDENCY DEPNAME INCLUDEFILE LIBRARY_NAMES_BASE SEARCHPATHLIST DEBUGSUFFIX) ################################################################################################ # this Macro is tailored to Mike and Torbens dependencies ################################################################################################ MACRO(SEARCH_3RDPARTY OSG_3RDPARTY_BIN) FIND_DEPENDENCY(TIFF tiff.h "libtiff;tiff" ${OSG_3RDPARTY_BIN} "D" "") FIND_DEPENDENCY(FREETYPE ft2build.h "freetype;freetype2311MT;freetype234;freetype234MT;freetype235;freetype237;freetype238;freetype244;freetype250;freetype27;" ${OSG_3RDPARTY_BIN} "d" "") IF(FREETYPE_FOUND) #forcing subsequent FindFreeType stuff to not search for other variables.... kind of a hack SET(FREETYPE_INCLUDE_DIR_ft2build ${FREETYPE_INCLUDE_DIR} CACHE PATH "" FORCE) SET(FREETYPE_INCLUDE_DIR_freetype2 ${FREETYPE_INCLUDE_DIR} CACHE PATH "" FORCE) MARK_AS_ADVANCED(FREETYPE_INCLUDE_DIR_ft2build FREETYPE_INCLUDE_DIR_freetype2) SET(FREETYPE_INCLUDE_DIRS "${FREETYPE_INCLUDE_DIR_ft2build};${FREETYPE_INCLUDE_DIR_freetype2}") ENDIF(FREETYPE_FOUND) FIND_DEPENDENCY(CURL curl/curl.h "libcurl;curllib;libcurl_imp" ${OSG_3RDPARTY_BIN} "D" "") FIND_DEPENDENCY(JPEG jpeglib.h "libjpeg;jpeg" ${OSG_3RDPARTY_BIN} "D" "") FIND_DEPENDENCY(GDAL gdal.h "gdal;gdal16" ${OSG_3RDPARTY_BIN} "d" "_i") FIND_DEPENDENCY(GLUT GL/glut.h glut32 ${OSG_3RDPARTY_BIN} "D" "") IF(GLUT_FOUND) #forcing subsequent FindGlut stuff to not search for other variables.... kind of a hack SET(GLUT_glut_LIBRARY ${GLUT_LIBRARY} CACHE FILEPATH "") MARK_AS_ADVANCED(GLUT_glut_LIBRARY) ENDIF(GLUT_FOUND) FIND_DEPENDENCY(GIFLIB gif_lib.h "ungif;libungif;giflib" ${OSG_3RDPARTY_BIN} "D" "") FIND_DEPENDENCY(ZLIB zlib.h "z;zlib;zlib1" ${OSG_3RDPARTY_BIN} "D" "") IF(ZLIB_FOUND) FIND_DEPENDENCY(PNG png.h "libpng;libpng13;libpng15;libpng16" ${OSG_3RDPARTY_BIN} "D" "") IF(PNG_FOUND) #forcing subsequent FindPNG stuff to not search for other variables.... kind of a hack SET(PNG_PNG_INCLUDE_DIR ${PNG_INCLUDE_DIR} CACHE FILEPATH "") MARK_AS_ADVANCED(PNG_PNG_INCLUDE_DIR) ENDIF(PNG_FOUND) ENDIF(ZLIB_FOUND) # CMakes default module to find libxml2 will not find the in FIND_DEPENDENCY(LIBXML2 libxml/xpath.h "libxml2" ${OSG_3RDPARTY_BIN} "D" "") IF(LIBXML2_FOUND) # The CMAKE find libxml module uses LIBXML2_LIBRARIES -> fill it.... kind of a hack SET(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY} CACHE FILEPATH "LibXML2 library for collada" FORCE) # SET(LIBXML2_XMLLINT_EXECUTABLE ${OSG_3RDPARTY_BIN}/bin/xmllint.exe CACHE FILEPATH "Path to xmllint executable" FORCE) ENDIF(LIBXML2_FOUND) #FIND_DEPENDENCY(DEPNAME INCLUDEFILE LIBRARY_NAMES_BASE SEARCHPATHLIST DEBUGSUFFIX EXSUFFIX) FIND_Package(NVTT) #luigi#INCLUDE(FindOSGDepends.cmake) ENDMACRO(SEARCH_3RDPARTY OSG_3RDPARTY_BIN) ################################################################################################ # this is code for handling optional 3RDPARTY usage ################################################################################################ OPTION(USE_3RDPARTY_BIN "Set to ON to use Mike or Torbens prebuilt dependencies situated side of OpenSceneGraph source. Use OFF for avoiding." ON) IF(USE_3RDPARTY_BIN) # Check Architecture IF( CMAKE_SIZEOF_VOID_P EQUAL 4 ) MESSAGE( STATUS "32 bit architecture detected" ) SET(DESTINATION_ARCH "x86") ENDIF() IF( CMAKE_SIZEOF_VOID_P EQUAL 8 ) MESSAGE( STATUS "64 bit architecture detected" ) SET(DESTINATION_ARCH "x64") ENDIF() GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_SOURCE_DIR} PATH) SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty") IF(NOT EXISTS ${TEST_3RDPARTY_DIR}) SET(3RDPARTY_DIR_BY_ENV $ENV{OSG_3RDPARTY_DIR}) IF(3RDPARTY_DIR_BY_ENV) MESSAGE( STATUS "3rdParty-Package ENV variable found:${3RDPARTY_DIR_BY_ENV}/${DESTINATION_ARCH}" ) SET(TEST_3RDPARTY_DIR "${3RDPARTY_DIR_BY_ENV}/${DESTINATION_ARCH}") ELSEIF(MSVC71) SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdParty_win32binaries_vs71") ELSEIF(MSVC80) SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdParty_win32binaries_vs80sp1") ELSEIF(MSVC90) SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdParty_win32binaries_vs90sp1") ENDIF() ENDIF(NOT EXISTS ${TEST_3RDPARTY_DIR}) SET(ACTUAL_3RDPARTY_DIR "${TEST_3RDPARTY_DIR}" CACHE PATH "Location of 3rdparty dependencies") SET(ACTUAL_3DPARTY_DIR "${ACTUAL_3RDPARTY_DIR}") # kept for backcompatibility IF(EXISTS ${ACTUAL_3RDPARTY_DIR}) SET (3rdPartyRoot ${ACTUAL_3RDPARTY_DIR}) SEARCH_3RDPARTY(${ACTUAL_3RDPARTY_DIR}) ENDIF(EXISTS ${ACTUAL_3RDPARTY_DIR}) ENDIF(USE_3RDPARTY_BIN) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindAVFoundation.cmake0000644000175000017500000000240313151044751025532 0ustar albertoalberto# Locate Apple AVFoundation (next-generation QTKit) # This module defines # AV_FOUNDATION_LIBRARY # AV_FOUNDATION_FOUND, if false, do not try to link to gdal # # $AV_FOUNDATION_DIR is an environment variable that would # correspond to the ./configure --prefix=$AV_FOUNDATION_DIR # # Created by Stephan Maximilian Huber IF(APPLE) FIND_LIBRARY(AV_FOUNDATION_LIBRARY AVFoundation) ENDIF() SET(AV_FOUNDATION_FOUND "NO") IF(AV_FOUNDATION_LIBRARY) SET(AV_FOUNDATION_FOUND "YES") ENDIF() IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) # AVFoundation exists ON iOS, too -- good support for SDK 6.0 and greater IF(${IPHONE_SDKVER} LESS "6.0") SET(AV_FOUNDATION_FOUND "NO") ELSE() SET(AV_FOUNDATION_FOUND "YES") ENDIF() ELSE() IF(APPLE) # AVFoundation exists since 10.7, but only 10.8 has all features necessary for OSG # so check the SDK-setting IF(${OSG_OSX_SDK_NAME} STREQUAL "macosx10.8" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.9" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.10" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.11") # nothing special here ;-) ELSE() MESSAGE("AVFoundation disabled for SDK < 10.8") SET(AV_FOUNDATION_FOUND "NO") ENDIF() ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGIFLIB.cmake0000644000175000017500000000265713151044751024144 0ustar albertoalberto# This module defines # GIFLIB_LIBRARY # GIFLIB_FOUND, if false, do not try to link # GIFLIB_INCLUDE_DIR, where to find the headers # # $GIFLIB_DIR is an environment variable that would # correspond to the ./configure --prefix=$GIFLIB_DIR # # Created by Eric Wing. FIND_PATH(GIFLIB_INCLUDE_DIR gif_lib.h PATHS $ENV{GIFLIB_DIR} NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(GIFLIB_INCLUDE_DIR gif_lib.h PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(GIFLIB_INCLUDE_DIR gif_lib.h PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(GIFLIB_LIBRARY NAMES gif ungif libgif libungif PATHS $ENV{GIFLIB_DIR} NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(GIFLIB_LIBRARY NAMES gif ungif libgif libungif PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(GIFLIB_LIBRARY NAMES gif ungif libgif libungif PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw /opt/local /opt/csw /opt /usr/freeware PATH_SUFFIXES lib64 lib ) SET(GIFLIB_FOUND "NO") IF(GIFLIB_LIBRARY AND GIFLIB_INCLUDE_DIR) SET(GIFLIB_FOUND "YES") ENDIF(GIFLIB_LIBRARY AND GIFLIB_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindFBX.cmake0000644000175000017500000001072313151044751023620 0ustar albertoalberto# Locate FBX # This module defines: # FBX_INCLUDE_DIR, where to find the headers # # FBX_LIBRARY, FBX_LIBRARY_DEBUG # FBX_FOUND # # $FBX_DIR is an environment variable that would # correspond to the ./configure --prefix=$FBX_DIR IF(APPLE) SET(FBX_LIBDIR "gcc4/ub") ELSEIF(CMAKE_COMPILER_IS_GNUCXX) SET(FBX_LIBDIR "gcc4") ELSEIF(MSVC80) SET(FBX_LIBDIR "vs2005") ELSEIF(MSVC90) SET(FBX_LIBDIR "vs2008") ELSEIF(MSVC10) SET(FBX_LIBDIR "vs2010") ELSEIF(MSVC11) SET(FBX_LIBDIR "vs2012") ELSEIF(MSVC12 OR MSVC_VERSION>1800) SET(FBX_LIBDIR "vs2013") ENDIF() IF(APPLE) # do nothing ELSEIF(CMAKE_CL_64) SET(FBX_LIBDIR ${FBX_LIBDIR}/x64) ELSEIF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SIZEOF_VOID_P EQUAL 8) SET(FBX_LIBDIR ${FBX_LIBDIR}/x64) ELSE() SET(FBX_LIBDIR ${FBX_LIBDIR}/x86) ENDIF() #try to use 2015.1 or 2014.2 version IF(APPLE) SET(FBX_LIBNAME "libfbxsdk") ELSEIF(CMAKE_COMPILER_IS_GNUCXX) SET(FBX_LIBNAME "fbxsdk") ELSE() SET(FBX_LIBNAME "libfbxsdk-md") ENDIF() SET(FBX_LIBNAME_DEBUG ${FBX_LIBNAME}d) SET( FBX_SEARCH_PATHS $ENV{FBX_DIR} "$ENV{ProgramW6432}/Autodesk/FBX/FBX SDK/2015.1" "$ENV{PROGRAMFILES}/Autodesk/FBX/FBX SDK/2015.1" "/Applications/Autodesk/FBX/FBX SDK/2015.1" /Applications/Autodesk/FBXSDK20151 "$ENV{ProgramW6432}/Autodesk/FBX/FBX SDK/2014.2" "$ENV{PROGRAMFILES}/Autodesk/FBX/FBX SDK/2014.2" "/Applications/Autodesk/FBX/FBX SDK/2014.2" /Applications/Autodesk/FBXSDK20142 ) # search for headers & debug/release libraries FIND_PATH(FBX_INCLUDE_DIR "fbxsdk.h" PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "include") FIND_LIBRARY( FBX_LIBRARY ${FBX_LIBNAME} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}/release" "lib/${FBX_LIBDIR}") #Once one of the calls succeeds the result variable will be set and stored in the cache so that no call will search again. #no debug d suffix, search in debug folder only FIND_LIBRARY( FBX_LIBRARY_DEBUG ${FBX_LIBNAME} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}/debug") FIND_LIBRARY( FBX_LIBRARY_DEBUG ${FBX_LIBNAME_DEBUG} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}") IF(FBX_LIBRARY AND FBX_LIBRARY_DEBUG AND FBX_INCLUDE_DIR) SET(FBX_FOUND "YES") ELSE() SET(FBX_FOUND "NO") ENDIF() IF(NOT FBX_FOUND) #try to use 2014.1 version IF(APPLE) SET(FBX_LIBNAME "fbxsdk-2014.1") ELSEIF(CMAKE_COMPILER_IS_GNUCXX) SET(FBX_LIBNAME "fbxsdk-2014.1") ELSE() SET(FBX_LIBNAME "fbxsdk-2014.1") ENDIF() SET(FBX_LIBNAME_DEBUG ${FBX_LIBNAME}d) SET( FBX_SEARCH_PATHS $ENV{FBX_DIR} "$ENV{ProgramW6432}/Autodesk/FBX/FBX SDK/2014.1" "$ENV{PROGRAMFILES}/Autodesk/FBX/FBX SDK/2014.1" "/Applications/Autodesk/FBX/FBX SDK/2014.1" /Applications/Autodesk/FBXSDK20141 ) # search for headers & debug/release libraries FIND_PATH(FBX_INCLUDE_DIR "fbxsdk.h" PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "include") FIND_LIBRARY( FBX_LIBRARY ${FBX_LIBNAME} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}") FIND_LIBRARY( FBX_LIBRARY_DEBUG ${FBX_LIBNAME_DEBUG} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}") IF(FBX_LIBRARY AND FBX_LIBRARY_DEBUG AND FBX_INCLUDE_DIR) SET(FBX_FOUND "YES") ELSE() SET(FBX_FOUND "NO") ENDIF() ENDIF() IF(NOT FBX_FOUND) #try to use 2013.3 version IF(APPLE) SET(FBX_LIBNAME "fbxsdk-2013.3-static") ELSEIF(CMAKE_COMPILER_IS_GNUCXX) SET(FBX_LIBNAME "fbxsdk-2013.3-static") ELSE() SET(FBX_LIBNAME "fbxsdk-2013.3-md") ENDIF() SET(FBX_LIBNAME_DEBUG ${FBX_LIBNAME}d) SET( FBX_SEARCH_PATHS $ENV{FBX_DIR} "$ENV{ProgramW6432}/Autodesk/FBX/FBX SDK/2013.3" "$ENV{PROGRAMFILES}/Autodesk/FBX/FBX SDK/2013.3" "/Applications/Autodesk/FBX/FBX SDK/2013.3" /Applications/Autodesk/FBXSDK20133 ) # search for headers & debug/release libraries FIND_PATH(FBX_INCLUDE_DIR "fbxsdk.h" PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "include") FIND_LIBRARY( FBX_LIBRARY ${FBX_LIBNAME} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}") FIND_LIBRARY( FBX_LIBRARY_DEBUG ${FBX_LIBNAME_DEBUG} PATHS ${FBX_SEARCH_PATHS} PATH_SUFFIXES "lib/${FBX_LIBDIR}") IF(FBX_LIBRARY AND FBX_LIBRARY_DEBUG AND FBX_INCLUDE_DIR) SET(FBX_FOUND "YES") ELSE() SET(FBX_FOUND "NO") ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindAsio.cmake0000644000175000017500000000070613151044751024074 0ustar albertoalberto# Locate ASIO-headers (http://think-async.com/Asio) # This module defines # ASIO_FOUND, if false, do not try to link to gdal # ASIO_INCLUDE_DIR, where to find the headers # # Created by Stephan Maximilian Huber FIND_PATH(ASIO_INCLUDE_DIR NAMES asio.hpp PATHS /usr/include /usr/local/include ) SET(ASIO_FOUND "NO") IF(ASIO_INCLUDE_DIR) FIND_PACKAGE( Boost 1.37 ) IF(Boost_FOUND) SET(ASIO_FOUND "YES") ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindOpenEXR.cmake0000644000175000017500000000402113151044751024453 0ustar albertoalberto# Locate OpenEXR # This module defines # OPENEXR_LIBRARY # OPENEXR_FOUND, if false, do not try to link to OpenEXR # OPENEXR_INCLUDE_DIR, where to find the headers # # $OPENEXR_DIR is an environment variable that would # correspond to the ./configure --prefix=$OPENEXR_DIR # # Created by Robert Osfield. FIND_PATH(OPENEXR_INCLUDE_DIR OpenEXR/ImfIO.h $ENV{OPENEXR_DIR}/include $ENV{OPENEXR_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) # Macro to find exr libraries (deduplicating search paths) # example: OPENEXR_FIND_VAR(OPENEXR_IlmImf_LIBRARY IlmImf) MACRO(OPENEXR_FIND_VAR varname libname) FIND_LIBRARY( ${varname} NAMES ${libname} PATHS $ENV{OPENEXR_DIR}/lib $ENV{OPENEXR_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) ENDMACRO(OPENEXR_FIND_VAR) # Macro to find exr libraries (and debug versions) # example: OPENEXR_FIND(IlmImf) MACRO(OPENEXR_FIND libname) OPENEXR_FIND_VAR(OPENEXR_${libname}_LIBRARY ${libname}) OPENEXR_FIND_VAR(OPENEXR_${libname}_LIBRARY_DEBUG ${libname}d) ENDMACRO(OPENEXR_FIND) OPENEXR_FIND(IlmImf) OPENEXR_FIND(IlmThread) OPENEXR_FIND(Iex) OPENEXR_FIND(Half) SET(OPENEXR_FOUND "NO") IF(OPENEXR_INCLUDE_DIR AND OPENEXR_IlmImf_LIBRARY AND OPENEXR_IlmThread_LIBRARY AND OPENEXR_Iex_LIBRARY AND OPENEXR_Half_LIBRARY) SET(OPENEXR_LIBRARIES ${OPENEXR_IlmImf_LIBRARY} ${OPENEXR_IlmThread_LIBRARY} ${OPENEXR_Half_LIBRARY} ${OPENEXR_Iex_LIBRARY} ) SET(OPENEXR_LIBRARIES_VARS OPENEXR_IlmImf_LIBRARY OPENEXR_IlmThread_LIBRARY OPENEXR_Half_LIBRARY OPENEXR_Iex_LIBRARY ) SET(OPENEXR_FOUND "YES") ENDIF(OPENEXR_INCLUDE_DIR AND OPENEXR_IlmImf_LIBRARY AND OPENEXR_IlmThread_LIBRARY AND OPENEXR_Iex_LIBRARY AND OPENEXR_Half_LIBRARY) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindAndroidNDK.cmake0000644000175000017500000000216713151044751025121 0ustar albertoalberto# Locate AndroidNDK # This module defines # ANDROID_NDK # ANDROID_FOUND, if false, do not try to use AndroidNDK # FIND_PATH(ANDROID_NDK ndk-build ${ANDROID_NDK} NO_DEFAULT_PATH ) IF(NOT ANDROID_NDK) FIND_PATH(ANDROID_NDK ndk-build $ENV{ANDROID_NDK} $ENV{ANDROID_ROOT} NO_DEFAULT_PATH ) ENDIF() IF(NOT ANDROID_NDK) FIND_PATH(ANDROID_NDK ndk-build # search for r5c ~/android-ndk-r5c ~/android_develop/android-ndk-r5c ~/ndk-r5c ~/android_develop/ndk-r5c # search for r5b ~/android-ndk-r5b ~/android_develop/android-ndk-r5b ~/ndk-r5b ~/android_develop/ndk-r5b # search for r5 ~/android-ndk-r5 ~/android_develop/android-ndk-r5 ~/ndk-r5 ~/android_develop/ndk-r5 # search for r4-crystax ~/android-ndk-r4-crystax ~/android_develop/android-ndk-r4-crystax ~/ndk-r4 ~/android_develop/ndk-r4 ) ENDIF() SET(ANDROID_FOUND "NO") IF(ANDROID_NDK) SET(ANDROID_FOUND "YES") MESSAGE(STATUS "Android NDK found in: ${ANDROID_NDK}") ENDIF(ANDROID_NDK) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/OsgCPack.cmake0000644000175000017500000001407613151044751024037 0ustar albertoalberto# This script sets up packaging targets for each "COMPONENT" as specified in INSTALL commands # # for each component a CPackConfig-.cmake is generated in the build tree # and a target is added to call cpack for it (e.g. package_openscenegaph # A target for generating a package with everything that gets INSTALLED is generated (package_openscenegraph-all) # A target for making all of the abaove packages is generated (package_ALL) # # package filenames are created on the form --[-]-[-static].tar.gz # ...where compiler optionally set using a cmake gui (OSG_CPACK_COMPILER). This script tries to guess compiler version for msvc generators # ...build_type matches CMAKE_BUILD_TYPE for all generators but the msvc ones # resolve architecture. The reason i "change" i686 to i386 is that debian packages # require i386 so this is for the future IF("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") SET(SYSTEM_ARCH "i386") ELSE() SET(SYSTEM_ARCH ${CMAKE_SYSTEM_PROCESSOR}) ENDIF() # set a default system name - use CMake setting (Linux|Windows|...) SET(SYSTEM_NAME ${CMAKE_SYSTEM_NAME}) #message(STATUS "CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}") #message(STATUS "CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}") # for msvc the SYSTEM_NAME is set win32/64 instead of "Windows" IF(MSVC) IF(CMAKE_CL_64) SET(SYSTEM_NAME "win64") ELSE() SET(SYSTEM_NAME "win32") ENDIF() ENDIF() # Guess the compiler (is this desired for other platforms than windows?) IF(NOT DEFINED OSG_CPACK_COMPILER) INCLUDE(OsgDetermineCompiler) ENDIF() # expose the compiler setting to the user SET(OSG_CPACK_COMPILER "${OSG_COMPILER}" CACHE STRING "This ia short string (vc90, vc80sp1, gcc-4.3, ...) describing your compiler. The string is used for creating package filenames") IF(OSG_CPACK_COMPILER) SET(OSG_CPACK_SYSTEM_SPEC_STRING ${SYSTEM_NAME}-${SYSTEM_ARCH}-${OSG_CPACK_COMPILER}) ELSE() SET(OSG_CPACK_SYSTEM_SPEC_STRING ${SYSTEM_NAME}-${SYSTEM_ARCH}) ENDIF() ## variables that apply to all packages SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${OPENSCENEGRAPH_VERSION}") # these goes for all platforms. Setting these stops the CPack.cmake script from generating options about other package compression formats (.z .tz, etc.) IF(WIN32) SET(CPACK_GENERATOR "ZIP" CACHE STRING "CPack package generator type (i.e ZIP,NSIS,TGZ,DEB,RPM, -- see CPack for valid stypes") ELSE() SET(CPACK_GENERATOR "TGZ" CACHE STRING "CPack package generator type (i.e ZIP,NSIS,TGZ,DEB,RPM, -- see CPack for valid stypes") ENDIF() SET(CPACK_SOURCE_GENERATOR "TGZ") # for ms visual studio we use it's internally defined variable to get the configuration (debug,release, ...) IF(MSVC_IDE) SET(OSG_CPACK_CONFIGURATION "$(OutDir)") SET(PACKAGE_TARGET_PREFIX "Package ") ELSE() # on un*x an empty CMAKE_BUILD_TYPE means release IF(CMAKE_BUILD_TYPE) SET(OSG_CPACK_CONFIGURATION ${CMAKE_BUILD_TYPE}) ELSE() SET(OSG_CPACK_CONFIGURATION "Release") ENDIF() SET(PACKAGE_TARGET_PREFIX "package_") ENDIF() # Get all defined components GET_CMAKE_PROPERTY(CPACK_COMPONENTS_ALL COMPONENTS) IF(NOT CPACK_COMPONENTS_ALL) # cmake 2.6.0 don't supply the COMPONENTS property. # I set it manually to be the packages that can always be packaged MESSAGE("When building packages please consider using cmake version 2.6.1 or above") SET(CPACK_COMPONENTS_ALL libopenscenegraph libopenthreads openscenegraph libopenscenegraph-dev libopenthreads-dev) ENDIF() # Create a target that will be used to generate all packages defined below SET(PACKAGE_ALL_TARGETNAME "${PACKAGE_TARGET_PREFIX}ALL") ADD_CUSTOM_TARGET(${PACKAGE_ALL_TARGETNAME}) MACRO(GENERATE_PACKAGING_TARGET package_name) SET(CPACK_PACKAGE_NAME ${package_name}) # the doc packages don't need a system-arch specification IF(${package} MATCHES -doc) SET(OSG_PACKAGE_FILE_NAME ${package_name}-${OPENSCENEGRAPH_VERSION}) ELSE() SET(OSG_PACKAGE_FILE_NAME ${package_name}-${OPENSCENEGRAPH_VERSION}-${OSG_CPACK_SYSTEM_SPEC_STRING}-${OSG_CPACK_CONFIGURATION}) IF(NOT DYNAMIC_OPENSCENEGRAPH) SET(OSG_PACKAGE_FILE_NAME ${OSG_PACKAGE_FILE_NAME}-static) ENDIF() ENDIF() CONFIGURE_FILE("${OpenSceneGraph_SOURCE_DIR}/CMakeModules/OsgCPackConfig.cmake.in" "${OpenSceneGraph_BINARY_DIR}/CPackConfig-${package_name}.cmake" IMMEDIATE) SET(PACKAGE_TARGETNAME "${PACKAGE_TARGET_PREFIX}${package_name}") # This is naive and will probably need fixing eventually IF(MSVC) SET(MOVE_COMMAND "move") ELSE() SET(MOVE_COMMAND "mv") ENDIF() # Set in and out archive filenames. Windows = zip, others = tar.gz IF(WIN32) SET(ARCHIVE_EXT "zip") ELSE() SET(ARCHIVE_EXT "tar.gz") ENDIF() # Create a target that creates the current package # and rename the package to give it proper filename ADD_CUSTOM_TARGET(${PACKAGE_TARGETNAME}) SET_TARGET_PROPERTIES(${PACKAGE_TARGETNAME} PROPERTIES FOLDER "Packaging") ADD_CUSTOM_COMMAND(TARGET ${PACKAGE_TARGETNAME} COMMAND ${CMAKE_CPACK_COMMAND} -C ${OSG_CPACK_CONFIGURATION} --config ${OpenSceneGraph_BINARY_DIR}/CPackConfig-${package_name}.cmake COMMENT "Run CPack packaging for ${package_name}..." ) # Add the exact same custom command to the all package generating target. # I can't use add_dependencies to do this because it would allow parallell building of packages so am going brute here ADD_CUSTOM_COMMAND(TARGET ${PACKAGE_ALL_TARGETNAME} COMMAND ${CMAKE_CPACK_COMMAND} -C ${OSG_CPACK_CONFIGURATION} --config ${OpenSceneGraph_BINARY_DIR}/CPackConfig-${package_name}.cmake ) SET_TARGET_PROPERTIES(${PACKAGE_ALL_TARGETNAME} PROPERTIES FOLDER "Packaging") ENDMACRO(GENERATE_PACKAGING_TARGET) # Create configs and targets for a package including all components SET(OSG_CPACK_COMPONENT ALL) GENERATE_PACKAGING_TARGET(openscenegraph-all) # Create configs and targets for each component FOREACH(package ${CPACK_COMPONENTS_ALL}) SET(OSG_CPACK_COMPONENT ${package}) GENERATE_PACKAGING_TARGET(${package}) ENDFOREACH() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindNVTT.cmake0000644000175000017500000000630213151044751023772 0ustar albertoalberto# Locate nvidia-texture-tools # This module defines # NVTT_LIBRARY # NVTT_FOUND, if false, do not try to link to nvtt # NVTT_INCLUDE_DIR, where to find the headers # FIND_PATH(NVTT_INCLUDE_DIR nvtt/nvtt.h PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES include ) # NVTT FIND_LIBRARY(NVTT_LIBRARY NAMES nvtt PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVTT_LIBRARY_DEBUG NAMES nvtt_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # NVIMAGE FIND_LIBRARY(NVIMAGE_LIBRARY NAMES nvimage PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVIMAGE_LIBRARY_DEBUG NAMES nvimage_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # NVMATH FIND_LIBRARY(NVMATH_LIBRARY NAMES nvmath PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVMATH_LIBRARY_DEBUG NAMES nvmath_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # NVCORE FIND_LIBRARY(NVCORE_LIBRARY NAMES nvcore PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVCORE_LIBRARY_DEBUG NAMES nvcore_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # NVTHREAD FIND_LIBRARY(NVTHREAD_LIBRARY NAMES nvthread PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVTHREAD_LIBRARY_DEBUG NAMES nvthread_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # SQUISH FIND_LIBRARY(NVSQUISH_LIBRARY NAMES squish PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVSQUISH_LIBRARY_DEBUG NAMES squish_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # BC6H FIND_LIBRARY(NVBC6H_LIBRARY NAMES bc6h PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVBC6H_LIBRARY_DEBUG NAMES bc6h_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) # BC7 FIND_LIBRARY(NVBC7_LIBRARY NAMES bc7 PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) FIND_LIBRARY(NVBC7_LIBRARY_DEBUG NAMES bc7_d PATHS /usr/local /usr $ENV{NVTT_DIR} ${3rdPartyRoot} PATH_SUFFIXES lib64 lib lib/shared lib/static lib64/static ) SET(NVTT_FOUND "NO") IF(NVTT_LIBRARY AND NVTT_INCLUDE_DIR) SET(NVTT_FOUND "YES") ENDIF(NVTT_LIBRARY AND NVTT_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindOpenVRML.cmake0000644000175000017500000000262613151044751024606 0ustar albertoalberto# Locate openvml library # This module defines # OPENVRML_LIBRARY # OPENVRML_FOUND, if false, do not try to link to vrml # OPENVRML_INCLUDE_DIR, where to find the headers # # $OPENVRML_DIR is an environment variable that would # correspond to the ./configure --prefix=$OPENVRML_DIR # # Created by Robert Osfield. # Modified for the debug library by Jean-Sbastien Guay. FIND_PATH(OPENVRML_INCLUDE_DIR openvrml/openvrml-common.h $ENV{OPENVRML_DIR}/include $ENV{OPENVRML_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(OPENVRML_LIBRARY NAMES openvrml PATHS $ENV{OPENVRML_DIR}/lib $ENV{OPENVRML_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(OPENVRML_LIBRARY_DEBUG NAMES openvrmld PATHS $ENV{OPENVRML_DIR}/lib $ENV{OPENVRML_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(OPENVRML_FOUND "NO") IF(OPENVRML_LIBRARY AND OPENVRML_INCLUDE_DIR) SET(OPENVRML_FOUND "YES") ENDIF(OPENVRML_LIBRARY AND OPENVRML_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindSDL2.cmake0000644000175000017500000001635413151044751023713 0ustar albertoalberto# - Locate SDL library # This module defines # SDL2_LIBRARY, the name of the library to link against # SDL2_FOUND, if false, do not try to link to SDL # SDL2_INCLUDE_DIR, where to find SDL.h # SDL2_VERSION_STRING, human-readable string containing the version of SDL # # This module responds to the flag: # SDL2_BUILDING_LIBRARY # If this is defined, then no SDL2_main will be linked in because # only applications need main(). # Otherwise, it is assumed you are building an application and this # module will attempt to locate and set the proper link flags # as part of the returned SDL2_LIBRARY variable. # # Don't forget to include SDLmain.h and SDLmain.m your project for the # OS X framework based version. (Other versions link to -lSDLmain which # this module will try to find on your behalf.) Also for OS X, this # module will automatically add the -framework Cocoa on your behalf. # # # Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration # and no SDL2_LIBRARY, it means CMake did not find your SDL library # (SDL.dll, libsdl.so, SDL.framework, etc). # Set SDL2_LIBRARY_TEMP to point to your SDL library, and configure again. # Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value # as appropriate. These values are used to generate the final SDL2_LIBRARY # variable, but when these values are unset, SDL2_LIBRARY does not get created. # # # $SDLDIR is an environment variable that would # correspond to the ./configure --prefix=$SDLDIR # used in building SDL. # l.e.galup 9-20-02 # # Modified by Eric Wing. # Added code to assist with automated building by using environmental variables # and providing a more controlled/consistent search behavior. # Added new modifications to recognize OS X frameworks and # additional Unix paths (FreeBSD, etc). # Also corrected the header search path to follow "proper" SDL guidelines. # Added a search for SDLmain which is needed by some platforms. # Added a search for threads which is needed by some platforms. # Added needed compile switches for MinGW. # # On OSX, this will prefer the Framework version (if found) over others. # People will have to manually change the cache values of # SDL2_LIBRARY to override this selection or set the CMake environment # CMAKE_INCLUDE_PATH to modify the search paths. # # Note that the header path has changed from SDL/SDL.h to just SDL.h # This needed to change because "proper" SDL convention # is #include "SDL.h", not . This is done for portability # reasons because not all systems place things in SDL/ (see FreeBSD). #============================================================================= # Copyright 2003-2009 Kitware, Inc. # Copyright 2012 Benjamin Eikel # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_path(SDL2_INCLUDE_DIR SDL.h HINTS ENV SDL2DIR PATH_SUFFIXES include/SDL2 ) # SDL-1.1 is the name used by FreeBSD ports... # don't confuse it for the version number. find_library(SDL2_LIBRARY_TEMP NAMES SDL2 HINTS ENV SDL2DIR PATH_SUFFIXES lib ) if(NOT SDL2_BUILDING_LIBRARY) if(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") # Non-OS X framework versions expect you to also dynamically link to # SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms # seem to provide SDLmain for compatibility even though they don't # necessarily need it. find_library(SDL2MAIN_LIBRARY NAMES SDL2main HINTS ENV SDL2DIR PATH_SUFFIXES lib PATHS /sw /opt/local /opt/csw /opt ) endif() endif() # SDL may require threads on your system. # The Apple build may not need an explicit flag because one of the # frameworks may already provide it. # But for non-OSX systems, I will use the CMake Threads package. if(NOT APPLE) find_package(Threads) endif() # MinGW needs an additional library, mwindows # It's total link flags should look like -lmingw32 -lSDLmain -lSDL -lmwindows # (Actually on second look, I think it only needs one of the m* libraries.) if(MINGW) set(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") endif() if(SDL2_LIBRARY_TEMP) # For SDLmain if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY) list(FIND SDL2_LIBRARY_TEMP "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX) if(_SDL2_MAIN_INDEX EQUAL -1) set(SDL2_LIBRARY_TEMP "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARY_TEMP}) endif() unset(_SDL2_MAIN_INDEX) endif() # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa. # CMake doesn't display the -framework Cocoa string in the UI even # though it actually is there if I modify a pre-used variable. # I think it has something to do with the CACHE STRING. # So I use a temporary variable until the end so I can set the # "real" variable in one-shot. if(APPLE) set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") endif() # For threads, as mentioned Apple doesn't need this. # In fact, there seems to be a problem if I used the Threads package # and try using this line, so I'm just skipping it entirely for OS X. if(NOT APPLE) set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) endif() # For MinGW library if(MINGW) set(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) endif() # Set the final string here so the GUI reflects the final state. set(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found") # Set the temp variable to INTERNAL so it is not seen in the CMake GUI set(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") endif() if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL2_version.h") file(STRINGS "${SDL2_INCLUDE_DIR}/SDL2_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_MAJOR_VERSION[ \t]+[0-9]+$") file(STRINGS "${SDL2_INCLUDE_DIR}/SDL2_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_MINOR_VERSION[ \t]+[0-9]+$") file(STRINGS "${SDL2_INCLUDE_DIR}/SDL2_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_PATCHLEVEL[ \t]+[0-9]+$") string(REGEX REPLACE "^#define[ \t]+SDL2_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}") string(REGEX REPLACE "^#define[ \t]+SDL2_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}") string(REGEX REPLACE "^#define[ \t]+SDL2_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}") set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH}) unset(SDL2_VERSION_MAJOR_LINE) unset(SDL2_VERSION_MINOR_LINE) unset(SDL2_VERSION_PATCH_LINE) unset(SDL2_VERSION_MAJOR) unset(SDL2_VERSION_MINOR) unset(SDL2_VERSION_PATCH) endif() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR VERSION_VAR SDL2_VERSION_STRING) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGStreamer.cmake0000644000175000017500000001700413151044751025071 0ustar albertoalberto# - Try to find GStreamer and its plugins # Once done, this will define # # GSTREAMER_FOUND - system has GStreamer # GSTREAMER_INCLUDE_DIRS - the GStreamer include directories # GSTREAMER_LIBRARIES - link these to use GStreamer # # Additionally, gstreamer-base is always looked for and required, and # the following related variables are defined: # # GSTREAMER_BASE_INCLUDE_DIRS - gstreamer-base's include directory # GSTREAMER_BASE_LIBRARIES - link to these to use gstreamer-base # # Optionally, the COMPONENTS keyword can be passed to find_package() # and GStreamer plugins can be looked for. Currently, the following # plugins can be searched, and they define the following variables if # found: # # gstreamer-app: GSTREAMER_APP_INCLUDE_DIRS and GSTREAMER_APP_LIBRARIES # gstreamer-audio: GSTREAMER_AUDIO_INCLUDE_DIRS and GSTREAMER_AUDIO_LIBRARIES # gstreamer-fft: GSTREAMER_FFT_INCLUDE_DIRS and GSTREAMER_FFT_LIBRARIES # gstreamer-pbutils: GSTREAMER_PBUTILS_INCLUDE_DIRS and GSTREAMER_PBUTILS_LIBRARIES # gstreamer-video: GSTREAMER_VIDEO_INCLUDE_DIRS and GSTREAMER_VIDEO_LIBRARIES # # Copyright (C) 2012 Raphael Kubo da Costa # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS # IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Helper macro to find a GStreamer plugin (or GStreamer itself) # _component_prefix is prepended to the _INCLUDE_DIRS and _LIBRARIES variables (eg. "GSTREAMER_AUDIO") # _pkgconfig_name is the component's pkg-config name (eg. "gstreamer-1.0", or "gstreamer-video-1.0"). # _header is the component's header, relative to the gstreamer-1.0 directory (eg. "gst/gst.h"). # _library is the component's library name (eg. "gstreamer-1.0" or "gstvideo-1.0") #macro(FIND_GSTREAMER_COMPONENT _component_prefix _pkgconfig_name _header _library) # pkg_check_modules(PC_${_component_prefix} QUIET ${_pkgconfig_name}) # # find_path(${_component_prefix}_INCLUDE_DIRS # NAMES ${_header} # HINTS ${PC_${_component_prefix}_INCLUDE_DIRS} ${PC_${_component_prefix}_INCLUDEDIR} # PATH_SUFFIXES gstreamer-1.0 # ) # # find_library(${_component_prefix}_LIBRARIES # NAMES ${_library} # HINTS ${PC_${_component_prefix}_LIBRARY_DIRS} ${PC_${_component_prefix}_LIBDIR} # ) #endmacro() if (WIN32) macro(FIND_GSTREAMER_COMPONENT _component_prefix _pkgconfig_name _header _library) find_path(${_component_prefix}_INCLUDE_DIRS NAMES ${_header} PATHS C:/gstreamer/1.0/x86_64/include PATH_SUFFIXES gstreamer-1.0 ) find_library(${_component_prefix}_LIBRARIES NAMES ${_library} PATHS C:/gstreamer/1.0/x86_64/lib ) endmacro() else () find_package(PkgConfig) macro(FIND_GSTREAMER_COMPONENT _component_prefix _pkgconfig_name _header _library) pkg_check_modules(${_component_prefix} QUIET ${_pkgconfig_name}) # find_path(${_component_prefix}_INCLUDE_DIRS # NAMES ${_header} # HINTS ${PC_${_component_prefix}_INCLUDE_DIRS} ${PC_${_component_prefix}_INCLUDEDIR} # PATH_SUFFIXES gstreamer-1.0 # ) # find_library(${_component_prefix}_LIBRARIES # NAMES ${_library} # HINTS ${PC_${_component_prefix}_LIBRARY_DIRS} ${PC_${_component_prefix}_LIBDIR} # ) endmacro() endif () # ------------------------ # 1. Find GStreamer itself # ------------------------ # 1.1. Find headers and libraries FIND_GSTREAMER_COMPONENT(GSTREAMER gstreamer-1.0 gst/gst.h gstreamer-1.0) FIND_GSTREAMER_COMPONENT(GSTREAMER_BASE gstreamer-base-1.0 gst/gst.h gstbase-1.0) # 1.2. Check GStreamer version if (GSTREAMER_INCLUDE_DIRS) if (EXISTS "${GSTREAMER_INCLUDE_DIRS}/gst/gstversion.h") file(READ "${GSTREAMER_INCLUDE_DIRS}/gst/gstversion.h" GSTREAMER_VERSION_CONTENTS) string(REGEX MATCH "#define +GST_VERSION_MAJOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") set(GSTREAMER_VERSION_MAJOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define +GST_VERSION_MINOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") set(GSTREAMER_VERSION_MINOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define +GST_VERSION_MICRO +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}") set(GSTREAMER_VERSION_MICRO "${CMAKE_MATCH_1}") set(GSTREAMER_VERSION "${GSTREAMER_VERSION_MAJOR}.${GSTREAMER_VERSION_MINOR}.${GSTREAMER_VERSION_MICRO}") endif () endif () if ("${GStreamer_FIND_VERSION}" VERSION_GREATER "${GSTREAMER_VERSION}") message(FATAL_ERROR "Required version (" ${GStreamer_FIND_VERSION} ") is higher than found version (" ${GSTREAMER_VERSION} ")") endif () # ------------------------- # 2. Find GStreamer plugins # ------------------------- FIND_GSTREAMER_COMPONENT(GSTREAMER_APP gstreamer-app-1.0 gst/app/gstappsink.h gstapp-1.0) FIND_GSTREAMER_COMPONENT(GSTREAMER_AUDIO gstreamer-audio-1.0 gst/audio/audio.h gstaudio-1.0) FIND_GSTREAMER_COMPONENT(GSTREAMER_FFT gstreamer-fft-1.0 gst/fft/gstfft.h gstfft-1.0) FIND_GSTREAMER_COMPONENT(GSTREAMER_PBUTILS gstreamer-pbutils-1.0 gst/pbutils/pbutils.h gstpbutils-1.0) FIND_GSTREAMER_COMPONENT(GSTREAMER_VIDEO gstreamer-video-1.0 gst/video/video.h gstvideo-1.0) # ------------------------------------------------ # 3. Process the COMPONENTS passed to FIND_PACKAGE # ------------------------------------------------ set(_GSTREAMER_REQUIRED_VARS GSTREAMER_INCLUDE_DIRS GSTREAMER_LIBRARIES GSTREAMER_VERSION GSTREAMER_BASE_INCLUDE_DIRS GSTREAMER_BASE_LIBRARIES) foreach (_component ${GStreamer_FIND_COMPONENTS}) set(_gst_component "GSTREAMER_${_component}") string(TOUPPER ${_gst_component} _UPPER_NAME) list(APPEND _GSTREAMER_REQUIRED_VARS ${_UPPER_NAME}_INCLUDE_DIRS ${_UPPER_NAME}_LIBRARIES) endforeach () include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GStreamer REQUIRED_VARS ${_GSTREAMER_REQUIRED_VARS} VERSION_VAR GSTREAMER_VERSION) mark_as_advanced( GSTREAMER_APP_INCLUDE_DIRS GSTREAMER_APP_LIBRARIES GSTREAMER_AUDIO_INCLUDE_DIRS GSTREAMER_AUDIO_LIBRARIES GSTREAMER_BASE_INCLUDE_DIRS GSTREAMER_BASE_LIBRARIES GSTREAMER_FFT_INCLUDE_DIRS GSTREAMER_FFT_LIBRARIES GSTREAMER_INCLUDE_DIRS GSTREAMER_LIBRARIES GSTREAMER_PBUTILS_INCLUDE_DIRS GSTREAMER_PBUTILS_LIBRARIES GSTREAMER_VIDEO_INCLUDE_DIRS GSTREAMER_VIDEO_LIBRARIES ) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/clean_directories0000755000175000017500000000032113151044751024773 0ustar albertoalbertofind . -name Makefile | xargs rm -rf find . -name cmake_install.cmake | xargs rm -rf find . -name CMakeFiles | xargs rm -rf rm -rf CMakeCache.txt cmake_uninstall.cmake install_manifest.txt rm -rf lib bin OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindFreetype.cmake0000644000175000017500000001406313151044751024765 0ustar albertoalberto#.rst: # FindFreetype # ------------ # # Locate FreeType library # # This module defines # # :: # # FREETYPE_LIBRARIES, the library to link against # FREETYPE_FOUND, if false, do not try to link to FREETYPE # FREETYPE_INCLUDE_DIRS, where to find headers. # FREETYPE_VERSION_STRING, the version of freetype found (since CMake 2.8.8) # This is the concatenation of the paths: # FREETYPE_INCLUDE_DIR_ft2build # FREETYPE_INCLUDE_DIR_freetype2 # # # # $FREETYPE_DIR is an environment variable that would correspond to the # ./configure --prefix=$FREETYPE_DIR used in building FREETYPE. #============================================================================= # Copyright 2000-2016 Kitware, Inc. # Copyright 2000-2011 Insight Software Consortium # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the names of Kitware, Inc., the Insight Software Consortium, # nor the names of their contributors may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= # Created by Eric Wing. # Modifications by Alexander Neundorf. # This file has been renamed to "FindFreetype.cmake" instead of the correct # "FindFreeType.cmake" in order to be compatible with the one from KDE4, Alex. # Ugh, FreeType seems to use some #include trickery which # makes this harder than it should be. It looks like they # put ft2build.h in a common/easier-to-find location which # then contains a #include to a more specific header in a # more specific location (#include ). # Then from there, they need to set a bunch of #define's # so you can do something like: # #include FT_FREETYPE_H # Unfortunately, using CMake's mechanisms like include_directories() # wants explicit full paths and this trickery doesn't work too well. # I'm going to attempt to cut out the middleman and hope # everything still works. # Adapted for OpenSceneGraph until the updates here for finding the debug Windows library freetyped are released with CMake set(FREETYPE_FIND_ARGS HINTS ENV FREETYPE_DIR PATHS /usr/X11R6 /usr/local/X11R6 /usr/local/X11 /usr/freeware ENV GTKMM_BASEPATH [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path] [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path] ) find_path( FREETYPE_INCLUDE_DIR_ft2build ft2build.h ${FREETYPE_FIND_ARGS} PATH_SUFFIXES include/freetype2 include freetype2 ) find_path( FREETYPE_INCLUDE_DIR_freetype2 NAMES freetype/config/ftheader.h config/ftheader.h ${FREETYPE_FIND_ARGS} PATH_SUFFIXES include/freetype2 include freetype2 ) if(NOT FREETYPE_LIBRARY) find_library(FREETYPE_LIBRARY_RELEASE NAMES freetype libfreetype freetype219 ${FREETYPE_FIND_ARGS} PATH_SUFFIXES lib ) find_library(FREETYPE_LIBRARY_DEBUG NAMES freetyped libfreetyped freetype219d ${FREETYPE_FIND_ARGS} PATH_SUFFIXES lib ) include(SelectLibraryConfigurations) #OSG Look in CMake Modules dir select_library_configurations(FREETYPE) endif() unset(FREETYPE_FIND_ARGS) # set the user variables if(FREETYPE_INCLUDE_DIR_ft2build AND FREETYPE_INCLUDE_DIR_freetype2) set(FREETYPE_INCLUDE_DIRS "${FREETYPE_INCLUDE_DIR_ft2build};${FREETYPE_INCLUDE_DIR_freetype2}") list(REMOVE_DUPLICATES FREETYPE_INCLUDE_DIRS) endif() set(FREETYPE_LIBRARIES "${FREETYPE_LIBRARY}") if(EXISTS "${FREETYPE_INCLUDE_DIR_freetype2}/freetype/freetype.h") set(FREETYPE_H "${FREETYPE_INCLUDE_DIR_freetype2}/freetype/freetype.h") elseif(EXISTS "${FREETYPE_INCLUDE_DIR_freetype2}/freetype.h") set(FREETYPE_H "${FREETYPE_INCLUDE_DIR_freetype2}/freetype.h") endif() if(FREETYPE_INCLUDE_DIR_freetype2 AND FREETYPE_H) file(STRINGS "${FREETYPE_H}" freetype_version_str REGEX "^#[\t ]*define[\t ]+FREETYPE_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$") unset(FREETYPE_VERSION_STRING) foreach(VPART MAJOR MINOR PATCH) foreach(VLINE ${freetype_version_str}) if(VLINE MATCHES "^#[\t ]*define[\t ]+FREETYPE_${VPART}[\t ]+([0-9]+)$") set(FREETYPE_VERSION_PART "${CMAKE_MATCH_1}") if(FREETYPE_VERSION_STRING) set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_STRING}.${FREETYPE_VERSION_PART}") else() set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_PART}") endif() unset(FREETYPE_VERSION_PART) endif() endforeach() endforeach() endif() # handle the QUIETLY and REQUIRED arguments and set FREETYPE_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) #OSG Look in CMake Modules dir find_package_handle_standard_args( Freetype REQUIRED_VARS FREETYPE_LIBRARY FREETYPE_INCLUDE_DIRS VERSION_VAR FREETYPE_VERSION_STRING ) mark_as_advanced( FREETYPE_INCLUDE_DIR_freetype2 FREETYPE_INCLUDE_DIR_ft2build ) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindCOLLADA.cmake0000644000175000017500000002447013151044751024244 0ustar albertoalberto# Locate Collada # This module defines: # COLLADA_INCLUDE_DIR, where to find the headers # # COLLADA_LIBRARY, COLLADA_LIBRARY_DEBUG # COLLADA_FOUND, if false, do not try to link to Collada dynamically # # COLLADA_LIBRARY_STATIC, COLLADA_LIBRARY_STATIC_DEBUG # COLLADA_STATIC_FOUND, if false, do not try to link to Collada statically # # $COLLADA_DIR is an environment variable that would # correspond to the ./configure --prefix=$COLLADA_DIR # # Created by Robert Osfield. # Check if COLLADA_DIR is set, otherwise use ACTUAL_3DPARTY_DIR: SET( COLLADA_ENV_VAR_AVAILABLE $ENV{COLLADA_DIR} ) IF ( COLLADA_ENV_VAR_AVAILABLE ) SET(COLLADA_DOM_ROOT "$ENV{COLLADA_DIR}/dom" CACHE PATH "Location of Collada DOM directory" FORCE) ELSE () SET(COLLADA_DOM_ROOT "${ACTUAL_3DPARTY_DIR}/include/1.4/dom" CACHE PATH "Location of Collada DOM directory" FORCE) ENDIF() IF(APPLE) SET(COLLADA_BUILDNAME "mac") ELSEIF(MINGW) SET(COLLADA_BUILDNAME "mingw") ELSEIF(MSVC14) SET(COLLADA_BUILDNAME "vc14") ELSEIF(MSVC12) SET(COLLADA_BUILDNAME "vc12") ELSEIF(MSVC11) SET(COLLADA_BUILDNAME "vc11") ELSEIF(MSVC10) SET(COLLADA_BUILDNAME "vc10") ELSEIF(MSVC90) SET(COLLADA_BUILDNAME "vc9") ELSEIF(MSVC80) SET(COLLADA_BUILDNAME "vc8") ELSE(APPLE) SET(COLLADA_BUILDNAME "linux") ENDIF(APPLE) FIND_PATH(COLLADA_INCLUDE_DIR dae.h ${COLLADA_DOM_ROOT}/include $ENV{COLLADA_DIR}/include $ENV{COLLADA_DIR} ~/Library/Frameworks /Library/Frameworks /opt/local/Library/Frameworks #macports /usr/local/include /usr/local/include/colladadom /usr/local/include/collada-dom /usr/local/include/collada-dom2.4 /usr/local/include/collada-dom2.2 /opt/local/include/collada-dom /opt/local/include/collada-dom2.4 /opt/local/include/collada-dom2.2 /usr/include/ /usr/include/colladadom /usr/include/collada-dom /usr/include/collada-dom2.4 /usr/include/collada-dom2.2 /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ${ACTUAL_3DPARTY_DIR}/include ) FIND_LIBRARY(COLLADA_DYNAMIC_LIBRARY NAMES collada_dom collada14dom Collada14Dom libcollada14dom21 libcollada14dom22 collada-dom2.4-dp collada-dom2.4-dp-vc120-mt PATHS ${COLLADA_DOM_ROOT}/build/${COLLADA_BUILDNAME}-1.4 ${COLLADA_DOM_ROOT} $ENV{COLLADA_DIR}/build/${COLLADA_BUILDNAME}-1.4 $ENV{COLLADA_DIR}/lib $ENV{COLLADA_DIR}/lib-dbg $ENV{COLLADA_DIR} ~/Library/Frameworks /Library/Frameworks /opt/local/Library/Frameworks #macports /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_DYNAMIC_LIBRARY_DEBUG NAMES collada_dom-d collada14dom-d Collada14Dom-d libcollada14dom21-d libcollada14dom22-d collada-dom2.4-dp-d collada-dom2.4-dp-vc120-mt-d PATHS ${COLLADA_DOM_ROOT}/build/${COLLADA_BUILDNAME}-1.4-d ${COLLADA_DOM_ROOT} $ENV{COLLADA_DIR}/build/${COLLADA_BUILDNAME}-1.4-d $ENV{COLLADA_DIR}/lib $ENV{COLLADA_DIR}/lib-dbg $ENV{COLLADA_DIR} ~/Library/Frameworks /Library/Frameworks /opt/local/Library/Frameworks #macports /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_STATIC_LIBRARY NAMES libcollada14dom21-s libcollada14dom22-s libcollada14dom.a PATHS ${COLLADA_DOM_ROOT}/build/${COLLADA_BUILDNAME}-1.4 $ENV{COLLADA_DIR}/build/${COLLADA_BUILDNAME}-1.4 $ENV{COLLADA_DIR}/lib $ENV{COLLADA_DIR}/lib-dbg $ENV{COLLADA_DIR} ~/Library/Frameworks /Library/Frameworks /opt/local/Library/Frameworks #macports /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_STATIC_LIBRARY_DEBUG NAMES collada_dom-sd collada14dom-sd libcollada14dom21-sd libcollada14dom22-sd libcollada14dom-d.a PATHS ${COLLADA_DOM_ROOT}/build/${COLLADA_BUILDNAME}-1.4-d $ENV{COLLADA_DIR}/build/${COLLADA_BUILDNAME}-1.4-d $ENV{COLLADA_DIR}/lib $ENV{COLLADA_DIR}/lib-dbg $ENV{COLLADA_DIR} ~/Library/Frameworks /Library/Frameworks /opt/local/Library/Frameworks #macports /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ${ACTUAL_3DPARTY_DIR}/lib ) # find extra libraries that the static linking requires FIND_PACKAGE(LibXml2) IF (LIBXML2_FOUND) SET(COLLADA_LIBXML_LIBRARY "${LIBXML2_LIBRARIES}" CACHE FILEPATH "" FORCE) ELSE(LIBXML2_FOUND) IF(WIN32) FIND_LIBRARY(COLLADA_LIBXML_LIBRARY NAMES libxml2 PATHS ${COLLADA_DOM_ROOT}/external-libs/libxml2/win32/lib ${COLLADA_DOM_ROOT}/external-libs/libxml2/mingw/lib ${ACTUAL_3DPARTY_DIR}/lib ) ENDIF(WIN32) ENDIF(LIBXML2_FOUND) FIND_PACKAGE(ZLIB) IF (ZLIB_FOUND) IF (ZLIB_LIBRARY_RELEASE) SET(COLLADA_ZLIB_LIBRARY "${ZLIB_LIBRARY_RELEASE}" CACHE FILEPATH "" FORCE) ELSE(ZLIB_LIBRARY_RELEASE) SET(COLLADA_ZLIB_LIBRARY "${ZLIB_LIBRARY}" CACHE FILEPATH "" FORCE) ENDIF(ZLIB_LIBRARY_RELEASE) IF (ZLIB_LIBRARY_DEBUG) SET(COLLADA_ZLIB_LIBRARY_DEBUG "${ZLIB_LIBRARY_DEBUG}" CACHE FILEPATH "" FORCE) ELSE(ZLIB_LIBRARY_DEBUG) SET(COLLADA_ZLIB_LIBRARY_DEBUG "${COLLADA_ZLIB_LIBRARY}" CACHE FILEPATH "" FORCE) ENDIF(ZLIB_LIBRARY_DEBUG) ELSE(ZLIB_FOUND) IF(WIN32) FIND_LIBRARY(COLLADA_ZLIB_LIBRARY NAMES zlib PATHS ${COLLADA_DOM_ROOT}/external-libs/libxml2/win32/lib ${COLLADA_DOM_ROOT}/external-libs/libxml2/mingw/lib ${ACTUAL_3DPARTY_DIR}/lib ) ENDIF(WIN32) ENDIF(ZLIB_FOUND) FIND_LIBRARY(COLLADA_PCRECPP_LIBRARY NAMES pcrecpp PATHS ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mac ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_PCRECPP_LIBRARY_DEBUG NAMES pcrecpp-d pcrecppd PATHS ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mac ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_PCRE_LIBRARY NAMES pcre PATHS ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mac ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_PCRE_LIBRARY_DEBUG NAMES pcre-d pcred PATHS ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mac ${COLLADA_DOM_ROOT}/external-libs/pcre/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_MINIZIP_LIBRARY NAMES minizip PATHS ${COLLADA_DOM_ROOT}/external-libs/minizip/win32/lib ${COLLADA_DOM_ROOT}/external-libs/minizip/mac ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_MINIZIP_LIBRARY_DEBUG NAMES minizip-d minizipD PATHS ${COLLADA_DOM_ROOT}/external-libs/minizip/win32/lib ${COLLADA_DOM_ROOT}/external-libs/minizip/mac ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_BOOST_FILESYSTEM_LIBRARY NAMES libboost_filesystem boost_filesystem boost_filesystem-mt libboost_filesystem-${COLLADA_BUILDNAME}0-mt libboost_filesystem-${COLLADA_BUILDNAME}0-mt-1_54 libboost_filesystem-${COLLADA_BUILDNAME}0-mt-1_55 libboost_filesystem-${COLLADA_BUILDNAME}0-mt-1_58 boost_filesystem-${COLLADA_BUILDNAME}0-mt-1_62 PATHS ${COLLADA_DOM_ROOT}/external-libs/boost/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/boost/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_BOOST_FILESYSTEM_LIBRARY_DEBUG NAMES libboost_filesystem-d boost_filesystem-d boost_filesystem-mt-d libboost_filesystem-${COLLADA_BUILDNAME}0-mt-gd libboost_filesystem-${COLLADA_BUILDNAME}0-mt-gd-1_54 libboost_filesystem-${COLLADA_BUILDNAME}0-mt-gd-1_55 libboost_filesystem-${COLLADA_BUILDNAME}0-mt-gd-1_58 boost_filesystem-${COLLADA_BUILDNAME}0-mt-gd-1_62 PATHS ${COLLADA_DOM_ROOT}/external-libs/boost/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/boost/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_BOOST_SYSTEM_LIBRARY NAMES libboost_system boost_system boost_system-mt libboost_system-${COLLADA_BUILDNAME}0-mt libboost_system-${COLLADA_BUILDNAME}0-mt-1_54 libboost_system-${COLLADA_BUILDNAME}0-mt-1_55 libboost_system-${COLLADA_BUILDNAME}0-mt-1_58 boost_system-${COLLADA_BUILDNAME}0-mt-1_62 PATHS ${COLLADA_DOM_ROOT}/external-libs/boost/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/boost/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) FIND_LIBRARY(COLLADA_BOOST_SYSTEM_LIBRARY_DEBUG NAMES libboost_system-d boost_system-d boost_system-mt-d libboost_system-${COLLADA_BUILDNAME}0-mt-gd libboost_system-${COLLADA_BUILDNAME}0-mt-gd-1_54 libboost_system-${COLLADA_BUILDNAME}0-mt-gd-1_55 libboost_system-${COLLADA_BUILDNAME}0-mt-gd-1_58 boost_system-${COLLADA_BUILDNAME}0-mt-gd-1_62 PATHS ${COLLADA_DOM_ROOT}/external-libs/boost/lib/${COLLADA_BUILDNAME} ${COLLADA_DOM_ROOT}/external-libs/boost/lib/mingw ${ACTUAL_3DPARTY_DIR}/lib ) SET(COLLADA_FOUND "NO") IF(COLLADA_DYNAMIC_LIBRARY OR COLLADA_STATIC_LIBRARY) IF (COLLADA_INCLUDE_DIR) SET(COLLADA_FOUND "YES") FIND_PATH(COLLADA_INCLUDE_DOMANY_DIR 1.4/dom/domAny.h ${COLLADA_INCLUDE_DIR} ) IF (COLLADA_INCLUDE_DOMANY_DIR) SET(COLLADA_DOM_2_4_OR_LATER TRUE) ELSEIF() SET(COLLADA_DOM_2_4_OR_LATER FALSE) ENDIF() ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindV8.cmake0000644000175000017500000000165513151044751023502 0ustar albertoalberto# Locate V8 # This module defines # V8_LIBRARY # V8_FOUND, if false, do not try to link to gdal # V8_INCLUDE_DIR, where to find the headers # # $V8_DIR is an environment variable that would # correspond to the ./configure --prefix=$V8_DIR # # Created by Robert Osfield (based on FindFLTK.cmake) FIND_PATH(V8_INCLUDE_DIR v8.h $ENV{V8_DIR}/include $ENV{V8_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(V8_LIBRARY NAMES v8 libv8 PATHS $ENV{V8_DIR}/lib $ENV{V8_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(V8_FOUND "NO") IF(V8_LIBRARY AND V8_INCLUDE_DIR) SET(V8_FOUND "YES") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGTA.cmake0000644000175000017500000000217613151044751023617 0ustar albertoalberto# Locate libgta # This module defines # GTA_FOUND, if false, do not try to link to libgta # GTA_INCLUDE_DIRS, where to find the headers # GTA_LIBRARIES # # $GTA_DIR is an environment variable that would # correspond to the ./configure --prefix=$GTA_DIR # used in building libgta. INCLUDE(FindPkgConfig OPTIONAL) IF(PKG_CONFIG_FOUND) INCLUDE(FindPkgConfig) PKG_CHECK_MODULES(GTA gta) ELSE(PKG_CONFIG_FOUND) FIND_PATH(GTA_INCLUDE_DIRS gta/gta.hpp $ENV{GTA_DIR}/include $ENV{GTA_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(GTA_LIBRARIES NAMES gta libgta PATHS $ENV{GTA_DIR}/lib $ENV{GTA_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(GTA_FOUND "NO") IF(GTA_LIBRARIES AND GTA_INCLUDE_DIRS) SET(GTA_FOUND "YES") ENDIF(GTA_LIBRARIES AND GTA_INCLUDE_DIRS) ENDIF(PKG_CONFIG_FOUND) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindZLIB.cmake0000644000175000017500000000226613151044751023744 0ustar albertoalberto# Locate zlib # This module defines # ZLIB_LIBRARY # ZLIB_FOUND, if false, do not try to link to zlib # ZLIB_INCLUDE_DIR, where to find the headers # # $ZLIB_DIR is an environment variable that would # correspond to the ./configure --prefix=$ZLIB_DIR # used in building zlib. # # Created by Ulrich Hertlein. # prefer FindZLIB from cmake distribution if(EXISTS ${CMAKE_ROOT}/Modules/FindZLIB.cmake) include(${CMAKE_ROOT}/Modules/FindZLIB.cmake) if(ZLIB_FOUND) return() endif() endif() FIND_PATH(ZLIB_INCLUDE_DIR zlib.h $ENV{ZLIB_DIR}/include $ENV{ZLIB_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(ZLIB_LIBRARY NAMES z libz zlib PATHS $ENV{ZLIB_DIR}/lib $ENV{ZLIB_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(ZLIB_FOUND "NO") IF(ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) SET(ZLIB_FOUND "YES") ENDIF(ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/OsgAndroidMacroUtils.cmake0000644000175000017500000001724513151044751026442 0ustar albertoalbertoMACRO(SETUP_ANDROID_LIBRARY LIB_NAME) #foreach(arg ${TARGET_LIBRARIES}) # set(MODULE_LIBS "${MODULE_LIBS} -l${arg}") #endforeach(arg ${TARGET_LIBRARIES}) foreach(arg ${TARGET_SRC}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" n_f ${arg}) IF ("${arg}" MATCHES ".*\\.c$" OR "${arg}" MATCHES ".*\\.cpp$") #We only include source files, not header files, this removes anoying warnings set(MODULE_SOURCES "${MODULE_SOURCES} ${n_f}") ENDIF() endforeach(arg ${TARGET_SRC}) #SET(MODULE_INCLUDES "${CMAKE_SOURCE_DIR}/include include") GET_DIRECTORY_PROPERTY(loc_includes INCLUDE_DIRECTORIES) foreach(arg ${loc_includes}) IF(NOT "${arg}" MATCHES "/usr/include" AND NOT "${arg}" MATCHES "/usr/local/include") set(MODULE_INCLUDES "${MODULE_INCLUDES} ${arg}") ENDIF() endforeach(arg ${loc_includes}) GET_DIRECTORY_PROPERTY(loc_definitions COMPILE_DEFINITIONS) foreach(arg ${loc_definitions}) set(DEFINITIONS "${DEFINITIONS} -D${arg}") endforeach(arg ${loc_definitions}) message(STATUS "##############Creating Android Makefile#################") message(STATUS "name: ${LIB_NAME}") set(MODULE_NAME ${LIB_NAME}) set(MODULE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(MODULE_FLAGS_C ${DEFINITIONS}) set(MODULE_FLAGS_CPP ${DEFINITIONS}) #TODO: determine if GLES2 or GLES IF(OSG_GLES1_AVAILABLE) SET(OPENGLES_LIBRARY -lGLESv1_CM) ELSEIF(OSG_GLES2_AVAILABLE) SET(OPENGLES_LIBRARY -lGLESv2) ENDIF() #${MODULE_LIBS} set(MODULE_LIBS_FLAGS "${OPENGLES_LIBRARY} -ldl") if(NOT CPP_EXTENSION) set(CPP_EXTENSION "cpp") endif() IF(NOT MODULE_USER_STATIC_OR_DYNAMIC) MESSAGE(FATAL_ERROR "Not defined MODULE_USER_STATIC_OR_DYNAMIC") ENDIF() IF("MODULE_USER_STATIC_OR_DYNAMIC" MATCHES "STATIC") SET(MODULE_BUILD_TYPE "\$\(BUILD_STATIC_LIBRARY\)") SET(MODULE_LIBS_SHARED " ") SET(MODULE_LIBS_STATIC ${TARGET_LIBRARIES}) ELSE() SET(MODULE_BUILD_TYPE "\$\(BUILD_SHARED_LIBRARY\)") SET(MODULE_LIBS_SHARED ${TARGET_LIBRARIES}) SET(MODULE_LIBS_STATIC " ") ENDIF() set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} ${LIB_NAME}") set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${CMAKE_CURRENT_BINARY_DIR}/Android.mk \n") configure_file("${OSG_ANDROID_TEMPLATES}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") ENDMACRO() MACRO(ANDROID_3RD_PARTY) ################################################ #JPEG ################################################ FIND_PATH(JPEG_INCLUDE_DIR Android.mk ${CMAKE_SOURCE_DIR}/3rdparty/libjpeg NO_CMAKE_FIND_ROOT_PATH ) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} libjpeg") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${JPEG_INCLUDE_DIR}/Android.mk \n") if(JPEG_INCLUDE_DIR) message(STATUS "Jpeg found ${JPEG_INCLUDE_DIR}" ) set(JPEG_FOUND "Yes") install(DIRECTORY 3rdparty/build/libjpeg/ DESTINATION ./ ) else(JPEG_INCLUDE_DIR) message(STATUS "Jpeg missing" ) endif() ################################################ #PNG ################################################ FIND_PATH(PNG_INCLUDE_DIR Android.mk ${CMAKE_SOURCE_DIR}/3rdparty/libpng NO_CMAKE_FIND_ROOT_PATH ) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} libpng") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${PNG_INCLUDE_DIR}/Android.mk \n") if(PNG_INCLUDE_DIR) message(STATUS "PNG found ${PNG_INCLUDE_DIR}" ) set(PNG_FOUND "Yes") install(DIRECTORY 3rdparty/build/libpng/ DESTINATION ./ ) else(PNG_INCLUDE_DIR) message(STATUS "PNG missing" ) endif() ################################################ #GIF ################################################ FIND_PATH(GIFLIB_INCLUDE_DIR Android.mk ${CMAKE_SOURCE_DIR}/3rdparty/giflib NO_CMAKE_FIND_ROOT_PATH ) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} libgif") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${GIFLIB_INCLUDE_DIR}/Android.mk \n") if(GIFLIB_INCLUDE_DIR) message(STATUS "GIF found ${GIFLIB_INCLUDE_DIR}" ) set(GIFLIB_FOUND "Yes") install(DIRECTORY 3rdparty/build/giflib/ DESTINATION ./ ) else(GIFLIB_INCLUDE_DIR) message(STATUS "GIF missing" ) endif() ################################################ #TIF ################################################ FIND_PATH(TIFF_INCLUDE_DIR Android.mk ${CMAKE_SOURCE_DIR}/3rdparty/libtiff NO_CMAKE_FIND_ROOT_PATH ) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} libtiff") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${TIFF_INCLUDE_DIR}/Android.mk \n") if(TIFF_INCLUDE_DIR) message(STATUS "TIF found ${TIFF_INCLUDE_DIR}" ) set(TIFF_FOUND "Yes") install(DIRECTORY 3rdparty/build/libtiff/ DESTINATION ./ ) else(TIFF_INCLUDE_DIR) message(STATUS "TIF missing" ) endif() ################################################ #ZLIB ################################################ #FIND_PATH(ZLIB_INCLUDE_DIR Android.mk # ${CMAKE_SOURCE_DIR}/3rdparty/zlib #) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} zlib") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${ZLIB_INCLUDE_DIR}/Android.mk \n") #if(ZLIB_INCLUDE_DIR) # message(STATUS "ZLIB found ${ZLIB_INCLUDE_DIR}" ) # set(ZLIB_FOUND "Yes") # install(DIRECTORY 3rdparty/build/libjpeg/ DESTINATION ./ ) #else(ZLIB_INCLUDE_DIR) # message(STATUS "ZLIB missing" ) #endif() ################################################ #CURL ################################################ FIND_PATH(CURL_DIR Android.mk ${CMAKE_SOURCE_DIR}/3rdparty/curl NO_CMAKE_FIND_ROOT_PATH ) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} libcurl") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${CURL_DIR}/Android.mk \n") set(CURL_INCLUDE_DIR ${CURL_DIR}/include) set(CURL_INCLUDE_DIRS ${CURL_DIR}/include) #Both are defined in FindCurl if(CURL_DIR) message(STATUS "Curl found ${CURL_DIR}" ) set(CURL_FOUND "Yes") install(DIRECTORY 3rdparty/build/curl/ DESTINATION ./ ) else(CURL_DIR) message(STATUS "Curl missing" ) endif() ################################################ #FREETYPE ################################################ FIND_PATH(FREETYPE_DIR Android.mk ${CMAKE_SOURCE_DIR}/3rdparty/freetype NO_CMAKE_FIND_ROOT_PATH ) #set(ENV{AND_OSG_LIB_NAMES} "$ENV{AND_OSG_LIB_NAMES} libft2") #set(ENV{AND_OSG_LIB_PATHS} "$ENV{AND_OSG_LIB_PATHS}include ${FREETYPE_DIR}/Android.mk \n") set(FREETYPE_INCLUDE_DIRS ${FREETYPE_DIR}/include ${FREETYPE_DIR}/include/freetype/config) if(FREETYPE_DIR) message(STATUS "FREETYPE found ${FREETYPE_DIR}" ) set(FREETYPE_FOUND "Yes") install(DIRECTORY 3rdparty/build/freetype/ DESTINATION ./ ) else(FREETYPE_DIR) message(STATUS "FREETYPE missing" ) endif() ################################################ #GDAL ################################################ FIND_PATH(GDAL_DIR gdal.h ${CMAKE_SOURCE_DIR}/3rdparty/gdal/include NO_CMAKE_FIND_ROOT_PATH ) set(GDAL_INCLUDE_DIR "${GDAL_DIR}") if(GDAL_DIR) message(STATUS "GDAL found ${GDAL_DIR}" ) set(GDAL_FOUND "Yes") install(DIRECTORY 3rdparty/build/gdal/ DESTINATION ./ ) else(GDAL_DIR) message(STATUS "GDAL missing" ) endif() ENDMACRO() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindDirectInput.cmake0000644000175000017500000000266413151044751025440 0ustar albertoalberto# Locate directinput # This module defines # DIRECTINPUT_LIBRARIES # DIRECTINPUT_FOUND, if false, do not try to link to directinput # DIRECTINPUT_INCLUDE_DIR, where to find the headers # # $DIRECTINPUT_DIR is an environment variable that would # point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) # # Created by Cedric Pinson. # SET( DIRECTINPUT_FOUND FALSE ) IF( WIN32 ) FIND_PATH( DIRECTINPUT_ROOT_DIR Include/D3D10.h PATHS $ENV{PATH} $ENV{PROGRAMFILES} ) FIND_PATH( DIRECTINPUT_INCLUDE_DIR dinput.h PATHS ${DIRECTINPUT_ROOT_DIR}/Include ) FIND_LIBRARY( DIRECTINPUT_LIBRARY dinput7.lib dinput8.lib PATHS ${DIRECTINPUT_ROOT_DIR}/lib/x86 ) FIND_LIBRARY( DIRECTINPUT_GUID_LIBRARY dxguid.lib PATHS ${DIRECTINPUT_ROOT_DIR}/lib/x86 ) FIND_LIBRARY( DIRECTINPUT_ERR_LIBRARY dxerr.lib PATHS ${DIRECTINPUT_ROOT_DIR}/lib/x86 ) SET( DIRECTINPUT_LIBRARIES ${DIRECTINPUT_LIBRARY} ${DIRECTINPUT_GUID_LIBRARY} ${DIRECTINPUT_ERR_LIBRARY} ) IF ( DIRECTINPUT_INCLUDE_DIR AND DIRECTINPUT_LIBRARIES ) SET( DIRECTINPUT_FOUND TRUE ) ENDIF ( DIRECTINPUT_INCLUDE_DIR AND DIRECTINPUT_LIBRARIES ) ENDIF( WIN32 ) MARK_AS_ADVANCED( DIRECTINPUT_FOUND ) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindLua52.cmake0000644000175000017500000000503313151044751024067 0ustar albertoalberto# Locate Lua library # This module defines # LUA51_FOUND, if false, do not try to link to Lua # LUA_LIBRARIES # LUA_INCLUDE_DIR, where to find lua.h # LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) # # Note that the expected include convention is # #include "lua.h" # and not # #include # This is because, the lua location is not standardized and may exist # in locations other than lua/ #============================================================================= # Copyright 2007-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_path(LUA_INCLUDE_DIR lua.h HINTS ENV LUA_DIR PATH_SUFFIXES include/lua52 include/lua5.2 include/lua include PATHS ~/Library/Frameworks /Library/Frameworks /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt ) find_library(LUA_LIBRARY NAMES lua52 lua5.2 lua-5.2 lua HINTS ENV LUA_DIR PATH_SUFFIXES lib PATHS ~/Library/Frameworks /Library/Frameworks /sw /opt/local /opt/csw /opt ) if(LUA_LIBRARY) # include the math library for Unix if(UNIX AND NOT APPLE) find_library(LUA_MATH_LIBRARY m) set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") # For Windows and Mac, don't need to explicitly include the math library else() set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") endif() endif() if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h") file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"") string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") unset(lua_version_str) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua52 REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR VERSION_VAR LUA_VERSION_STRING) mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindXine.cmake0000644000175000017500000000173013151044751024102 0ustar albertoalberto# Locate gdal # This module defines # XINE_LIBRARY # XINE_FOUND, if false, do not try to link to gdal # XINE_INCLUDE_DIR, where to find the headers # # $XINE_DIR is an environment variable that would # correspond to the ./configure --prefix=$XINE_DIR # # Created by Robert Osfield. FIND_PATH(XINE_INCLUDE_DIR xine.h $ENV{XINE_DIR}/include $ENV{XINE_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(XINE_LIBRARY NAMES xine PATHS $ENV{XINE_DIR}/lib $ENV{XINE_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(XINE_FOUND "NO") IF(XINE_LIBRARY AND XINE_INCLUDE_DIR) SET(XINE_FOUND "YES") ENDIF(XINE_LIBRARY AND XINE_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/OsgDetermineCompiler.cmake0000644000175000017500000000510013151044751026451 0ustar albertoalberto# - If Visual Studio is being used, this script sets the variable OSG_COMPILER # The principal reason for this is due to MSVC 8.0 SP0 vs SP1 builds. # # Variable: # OSG_COMPILER # # Not currently used... #IF(CMAKE_COMPILER_IS_GNUCXX) # EXEC_PROGRAM( # ${CMAKE_CXX_COMPILER} # ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion # OUTPUT_VARIABLE gcc_compiler_version # ) # #MESSAGE("GCC Version: ${gcc_compiler_version}") IF(MSVC60) SET(OSG_COMPILER "vc60") ELSEIF(MSVC70) SET(OSG_COMPILER "vc70") ELSEIF(MSVC71) SET(OSG_COMPILER "vc71") ELSEIF(MSVC80) SET(OSG_COMPILER "vc80") ELSEIF(MSVC90) SET(OSG_COMPILER "vc90") ENDIF() IF(MSVC80) MESSAGE(STATUS "Checking if compiler has service pack 1 installed...") FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx" "int main() {return 0;}\n") TRY_COMPILE(_TRY_RESULT ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx CMAKE_FLAGS -D CMAKE_VERBOSE_MAKEFILE=ON OUTPUT_VARIABLE OUTPUT ) IF(_TRY_RESULT) # parse for exact compiler version STRING(REGEX MATCH "Compiler Version [0-9]+.[0-9]+.[0-9]+.[0-9]+" vc_compiler_version "${OUTPUT}") IF(vc_compiler_version) #MESSAGE("${vc_compiler_version}") STRING(REGEX MATCHALL "[0-9]+" CL_VERSION_LIST "${vc_compiler_version}") LIST(GET CL_VERSION_LIST 0 CL_MAJOR_VERSION) LIST(GET CL_VERSION_LIST 1 CL_MINOR_VERSION) LIST(GET CL_VERSION_LIST 2 CL_PATCH_VERSION) LIST(GET CL_VERSION_LIST 3 CL_EXTRA_VERSION) ENDIF(vc_compiler_version) # Standard vc80 is 14.00.50727.42, sp1 14.00.50727.762, sp2? # Standard vc90 is 9.0.30729.1, sp1 ? IF(CL_EXTRA_VERSION EQUAL 762) SET(OSG_COMPILER "vc80sp1") ELSE(CL_EXTRA_VERSION EQUAL 762) SET(OSG_COMPILER "vc80") ENDIF(CL_EXTRA_VERSION EQUAL 762) # parse for exact visual studio version #IF(MSVC_IDE) # string(REGEX MATCH "Visual Studio Version [0-9]+.[0-9]+.[0-9]+.[0-9]+" vs_version "${OUTPUT}") # IF(vs_version) # MESSAGE("${vs_version}") # string(REGEX MATCHALL "[0-9]+" VS_VERSION_LIST "${vs_version}") # list(GET VS_VERSION_LIST 0 VS_MAJOR_VERSION) # list(GET VS_VERSION_LIST 1 VS_MINOR_VERSION) # list(GET VS_VERSION_LIST 2 VS_PATCH_VERSION) # list(GET VS_VERSION_LIST 3 VS_EXTRA_VERSION) # ENDIF(vs_version) #ENDIF(MSVC_IDE) ENDIF(_TRY_RESULT) ENDIF(MSVC80) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindJasper.cmake0000644000175000017500000000332213151044751024422 0ustar albertoalberto# Locate gdal # This module defines # JASPER_LIBRARY # JASPER_FOUND, if false, do not try to link to gdal # JASPER_INCLUDE_DIR, where to find the headers # # $JASPER_DIR is an environment variable that would # correspond to the ./configure --prefix=$JASPER_DIR # # Created by Robert Osfield. # prefer FindJasper from cmake distribution if(EXISTS ${CMAKE_ROOT}/Modules/FindJasper.cmake) include(${CMAKE_ROOT}/Modules/FindJasper.cmake) if(JASPER_FOUND) return() endif() endif() FIND_PATH(JASPER_INCLUDE_DIR jasper/jasper.h $ENV{JASPER_DIR}/include $ENV{JASPER_DIR}/src/libjasper/include $ENV{JASPER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(JASPER_LIBRARY NAMES jasper libjasper PATHS $ENV{JASPER_DIR}/lib $ENV{JASPER_DIR}/src/libjasper/lib $ENV{JASPER_DIR}/src/msvc/Win32_Release $ENV{JASPER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(JASPER_LIBRARY_DEBUG NAMES jasper libjasper jasperd libjasperd PATHS $ENV{JASPER_DIR}/lib $ENV{JASPER_DIR}/src/libjasper/lib $ENV{JASPER_DIR}/src/msvc/Win32_Debug $ENV{JASPER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(JASPER_FOUND "NO") IF(JASPER_LIBRARY AND JASPER_INCLUDE_DIR) SET(JASPER_FOUND "YES") ENDIF(JASPER_LIBRARY AND JASPER_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindLibVNCServer.cmake0000644000175000017500000000263513151044751025450 0ustar albertoalberto# Locate libvncserver # This module defines # LIBVNCSERVER_LIBRARY # LIBVNCSERVER_FOUND, if false, do not try to link to libvncserver # LIBVNCSERVER_INCLUDE_DIR, where to find the headers # # $LIBVNCSERVER_DIR is an environment variable that would # correspond to the ./configure --prefix=$LIBVNCSERVER_DIR # used in building libvncserver. FIND_PATH(LIBVNCSERVER_INCLUDE_DIR rfb/rfb.h $ENV{LIBVNCSERVER_DIR}/include $ENV{LIBVNCSERVER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) FIND_LIBRARY(LIBVNCCLIENT_LIBRARY NAMES vncclient PATHS $ENV{LIBVNCSERVER_DIR}/lib $ENV{LIBVNCSERVER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(LIBVNCSERVER_LIBRARY NAMES vncserver PATHS $ENV{LIBVNCSERVER_DIR}/lib $ENV{LIBVNCSERVER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) SET(LIBVNCSERVER_FOUND "NO") IF(LIBVNCSERVER_LIBRARY AND LIBVNCSERVER_INCLUDE_DIR) SET(LIBVNCSERVER_FOUND "YES") ENDIF(LIBVNCSERVER_LIBRARY AND LIBVNCSERVER_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindQuickTime.cmake0000644000175000017500000000460213151044751025073 0ustar albertoalberto# Locate QuickTime # This module defines # QUICKTIME_LIBRARY # QUICKTIME_FOUND, if false, do not try to link to gdal # QUICKTIME_INCLUDE_DIR, where to find the headers # # $QUICKTIME_DIR is an environment variable that would # correspond to the ./configure --prefix=$QUICKTIME_DIR # # Created by Eric Wing. # QuickTime on OS X looks different than QuickTime for Windows, # so I am going to case the two. IF(APPLE) FIND_PATH(QUICKTIME_INCLUDE_DIR QuickTime/QuickTime.h) FIND_LIBRARY(QUICKTIME_LIBRARY QuickTime) ELSE() FIND_PATH(QUICKTIME_INCLUDE_DIR QuickTime.h $ENV{QUICKTIME_DIR}/include $ENV{QUICKTIME_DIR} NO_DEFAULT_PATH ) FIND_PATH(QUICKTIME_INCLUDE_DIR QuickTime.h PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(QUICKTIME_INCLUDE_DIR QuickTime.h) FIND_LIBRARY(QUICKTIME_LIBRARY QuickTime $ENV{QUICKTIME_DIR}/lib $ENV{QUICKTIME_DIR} NO_DEFAULT_PATH ) FIND_LIBRARY(QUICKTIME_LIBRARY QuickTime PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(QUICKTIME_LIBRARY QuickTime) ENDIF() SET(QUICKTIME_FOUND "NO") IF(QUICKTIME_LIBRARY AND QUICKTIME_INCLUDE_DIR) SET(QUICKTIME_FOUND "YES") ENDIF() IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) SET(QUICKTIME_FOUND "NO") ELSE() IF(APPLE) #Quicktime is not supported under 64bit OSX build so we need to detect it and disable it. #First check to see if we are running with a native 64-bit compiler (10.6 default) and implicit arch IF(NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SIZEOF_VOID_P EQUAL 8) SET(QUICKTIME_FOUND "NO") ELSE() #Otherwise check to see if 64-bit is explicitly called for. LIST(FIND CMAKE_OSX_ARCHITECTURES "x86_64" has64Compile) IF(NOT has64Compile EQUAL -1) SET(QUICKTIME_FOUND "NO") ENDIF() ENDIF() # Disable quicktime for >= 10.7, as it's officially deprecated IF(${OSG_OSX_SDK_NAME} STREQUAL "macosx10.7" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.8" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.9" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.10") MESSAGE("disabling quicktime because it's not supported by the selected SDK ${OSG_OSX_SDK_NAME}") SET(QUICKTIME_FOUND "NO") ENDIF() ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/OsgMacroUtils.cmake0000644000175000017500000006575113151044751025146 0ustar albertoalberto ####################################################################################################### # macro for linking libraries that come from Findxxxx commands, so there is a variable that contains the # full path of the library name. in order to differentiate release and debug, this macro get the # NAME of the variables, so the macro gets as arguments the target name and the following list of parameters # is intended as a list of variable names each one containing the path of the libraries to link to # The existence of a variable name with _DEBUG appended is tested and, in case it' s value is used # for linking to when in debug mode # the content of this library for linking when in debugging ####################################################################################################### # VALID_BUILDER_VERSION: used for replacing CMAKE_VERSION (available in v2.6.3 RC9) and VERSION_GREATER/VERSION_LESS (available in 2.6.2 RC4). # This can be replaced by "IF(${CMAKE_VERSION} VERSION_LESS "x.y.z")" from 2.6.4. SET(VALID_BUILDER_VERSION OFF) MACRO(BUILDER_VERSION_GREATER MAJOR_VER MINOR_VER PATCH_VER) SET(VALID_BUILDER_VERSION OFF) IF(CMAKE_MAJOR_VERSION GREATER ${MAJOR_VER}) SET(VALID_BUILDER_VERSION ON) ELSEIF(CMAKE_MAJOR_VERSION EQUAL ${MAJOR_VER}) IF(CMAKE_MINOR_VERSION GREATER ${MINOR_VER}) SET(VALID_BUILDER_VERSION ON) ELSEIF(CMAKE_MINOR_VERSION EQUAL ${MINOR_VER}) IF(CMAKE_PATCH_VERSION GREATER ${PATCH_VER}) SET(VALID_BUILDER_VERSION ON) ENDIF(CMAKE_PATCH_VERSION GREATER ${PATCH_VER}) ENDIF() ENDIF() ENDMACRO(BUILDER_VERSION_GREATER MAJOR_VER MINOR_VER PATCH_VER) # CMAKE24: if CMake version is <2.6.0. SET(CMAKE24 OFF) IF(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} LESS 5) SET(CMAKE24 ON) ENDIF(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} LESS 5) # CMAKE_VERSION_TEST: Define whether "IF(${CMAKE_VERSION} VERSION_LESS "x.y.z")" can be used or not. BUILDER_VERSION_GREATER(2 6 3) SET(CMAKE_VERSION_TEST ${VALID_BUILDER_VERSION}) # >= 2.6.4 SET(VALID_BUILDER_VERSION OFF) MACRO(LINK_WITH_VARIABLES TRGTNAME) FOREACH(varname ${ARGN}) IF(${varname}_DEBUG) IF(${varname}_RELEASE) TARGET_LINK_LIBRARIES(${TRGTNAME} optimized "${${varname}_RELEASE}" debug "${${varname}_DEBUG}") ELSE(${varname}_RELEASE) TARGET_LINK_LIBRARIES(${TRGTNAME} optimized "${${varname}}" debug "${${varname}_DEBUG}") ENDIF(${varname}_RELEASE) ELSE(${varname}_DEBUG) TARGET_LINK_LIBRARIES(${TRGTNAME} "${${varname}}" ) ENDIF(${varname}_DEBUG) ENDFOREACH(varname) ENDMACRO(LINK_WITH_VARIABLES TRGTNAME) MACRO(LINK_INTERNAL TRGTNAME) IF(NOT CMAKE24) TARGET_LINK_LIBRARIES(${TRGTNAME} ${ARGN}) ELSE(NOT CMAKE24) FOREACH(LINKLIB ${ARGN}) IF(MSVC AND OSG_MSVC_VERSIONED_DLL) #when using versioned names, the .dll name differ from .lib name, there is a problem with that: #CMake 2.4.7, at least seem to use PREFIX instead of IMPORT_PREFIX for computing linkage info to use into projects, # so we full path name to specify linkage, this prevent automatic inferencing of dependencies, so we add explicit depemdencies #to library targets used TARGET_LINK_LIBRARIES(${TRGTNAME} optimized "${OUTPUT_LIBDIR}/${LINKLIB}${CMAKE_RELEASE_POSTFIX}.lib" debug "${OUTPUT_LIBDIR}/${LINKLIB}${CMAKE_DEBUG_POSTFIX}.lib") ADD_DEPENDENCIES(${TRGTNAME} ${LINKLIB}) ELSE(MSVC AND OSG_MSVC_VERSIONED_DLL) TARGET_LINK_LIBRARIES(${TRGTNAME} optimized "${LINKLIB}${CMAKE_RELEASE_POSTFIX}" debug "${LINKLIB}${CMAKE_DEBUG_POSTFIX}") ENDIF(MSVC AND OSG_MSVC_VERSIONED_DLL) ENDFOREACH(LINKLIB) ENDIF(NOT CMAKE24) ENDMACRO(LINK_INTERNAL TRGTNAME) MACRO(LINK_EXTERNAL TRGTNAME) FOREACH(LINKLIB ${ARGN}) TARGET_LINK_LIBRARIES(${TRGTNAME} "${LINKLIB}" ) ENDFOREACH(LINKLIB) ENDMACRO(LINK_EXTERNAL TRGTNAME) ####################################################################################################### # macro for common setup of core libraries: it links OPENGL_LIBRARIES in undifferentiated mode ####################################################################################################### MACRO(LINK_CORELIB_DEFAULT CORELIB_NAME) #SET(ALL_GL_LIBRARIES ${OPENGL_LIBRARIES}) SET(ALL_GL_LIBRARIES ${OPENGL_gl_LIBRARY}) IF (OSG_GLES1_AVAILABLE OR OSG_GLES2_AVAILABLE) SET(ALL_GL_LIBRARIES ${ALL_GL_LIBRARIES} ${OPENGL_egl_LIBRARY}) ENDIF() LINK_EXTERNAL(${CORELIB_NAME} ${ALL_GL_LIBRARIES}) LINK_WITH_VARIABLES(${CORELIB_NAME} OPENTHREADS_LIBRARY) IF(OPENSCENEGRAPH_SONAMES) SET_TARGET_PROPERTIES(${CORELIB_NAME} PROPERTIES VERSION ${OPENSCENEGRAPH_VERSION} SOVERSION ${OPENSCENEGRAPH_SOVERSION}) ENDIF(OPENSCENEGRAPH_SONAMES) ENDMACRO(LINK_CORELIB_DEFAULT CORELIB_NAME) ####################################################################################################### # macro for common setup of plugins, examples and applications it expect some variables to be set: # either within the local CMakeLists or higher in hierarchy # TARGET_NAME is the name of the folder and of the actually .exe or .so or .dll # TARGET_TARGETNAME is the name of the target , this get buit out of a prefix, if present and TARGET_TARGETNAME # TARGET_SRC are the sources of the target # TARGET_H are the eventual headers of the target # TARGET_LIBRARIES are the libraries to link to that are internal to the project and have d suffix for debug # TARGET_EXTERNAL_LIBRARIES are external libraries and are not differentiated with d suffix # TARGET_LABEL is the label IDE should show up for targets ########################################################################################################## MACRO(SETUP_LINK_LIBRARIES) ###################################################################### # # This set up the libraries to link to, it assumes there are two variable: one common for a group of examples or plugins # kept in the variable TARGET_COMMON_LIBRARIES and an example or plugin specific kept in TARGET_ADDED_LIBRARIES # they are combined in a single list checked for unicity # the suffix ${CMAKE_DEBUG_POSTFIX} is used for differentiating optimized and debug # # a second variable TARGET_EXTERNAL_LIBRARIES hold the list of libraries not differentiated between debug and optimized ################################################################################## SET(TARGET_LIBRARIES ${TARGET_COMMON_LIBRARIES}) FOREACH(LINKLIB ${TARGET_ADDED_LIBRARIES}) SET(TO_INSERT TRUE) FOREACH (value ${TARGET_COMMON_LIBRARIES}) IF ("${value}" STREQUAL "${LINKLIB}") SET(TO_INSERT FALSE) ENDIF ("${value}" STREQUAL "${LINKLIB}") ENDFOREACH (value ${TARGET_COMMON_LIBRARIES}) IF(TO_INSERT) LIST(APPEND TARGET_LIBRARIES ${LINKLIB}) ENDIF(TO_INSERT) ENDFOREACH(LINKLIB) #SET(ALL_GL_LIBRARIES ${OPENGL_LIBRARIES}) SET(ALL_GL_LIBRARIES ${OPENGL_gl_LIBRARY}) IF (OSG_GLES1_AVAILABLE OR OSG_GLES2_AVAILABLE) SET(ALL_GL_LIBRARIES ${ALL_GL_LIBRARIES} ${OPENGL_egl_LIBRARY}) ENDIF() # FOREACH(LINKLIB ${TARGET_LIBRARIES}) # TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME} optimized ${LINKLIB} debug "${LINKLIB}${CMAKE_DEBUG_POSTFIX}") # ENDFOREACH(LINKLIB) LINK_INTERNAL(${TARGET_TARGETNAME} ${TARGET_LIBRARIES}) # FOREACH(LINKLIB ${TARGET_EXTERNAL_LIBRARIES}) # TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME} ${LINKLIB}) # ENDFOREACH(LINKLIB) TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME} ${TARGET_EXTERNAL_LIBRARIES}) IF(TARGET_LIBRARIES_VARS) LINK_WITH_VARIABLES(${TARGET_TARGETNAME} ${TARGET_LIBRARIES_VARS}) ENDIF(TARGET_LIBRARIES_VARS) IF(MSVC AND OSG_MSVC_VERSIONED_DLL) #when using full path name to specify linkage, it seems that already linked libs must be specified LINK_EXTERNAL(${TARGET_TARGETNAME} ${ALL_GL_LIBRARIES}) ENDIF(MSVC AND OSG_MSVC_VERSIONED_DLL) ENDMACRO(SETUP_LINK_LIBRARIES) ############################################################################################ # this is the common set of command for all the plugins # # Sets the output directory property for CMake >= 2.6.0, giving an output path RELATIVE to default one MACRO(SET_OUTPUT_DIR_PROPERTY_260 TARGET_TARGETNAME RELATIVE_OUTDIR) BUILDER_VERSION_GREATER(2 8 0) IF(NOT VALID_BUILDER_VERSION) # If CMake <= 2.8.0 (Testing CMAKE_VERSION is possible in >= 2.6.4) IF(MSVC_IDE) # Using the "prefix" hack SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PREFIX "../${RELATIVE_OUTDIR}/") ELSE(MSVC_IDE) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PREFIX "${RELATIVE_OUTDIR}/") ENDIF(MSVC_IDE) ELSE(NOT VALID_BUILDER_VERSION) # Using the output directory properties # Global properties (All generators but VS & Xcode) FILE(TO_CMAKE_PATH TMPVAR "CMAKE_ARCHIVE_OUTPUT_DIRECTORY/${RELATIVE_OUTDIR}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${TMPVAR}") FILE(TO_CMAKE_PATH TMPVAR "CMAKE_RUNTIME_OUTPUT_DIRECTORY/${RELATIVE_OUTDIR}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TMPVAR}") FILE(TO_CMAKE_PATH TMPVAR "CMAKE_LIBRARY_OUTPUT_DIRECTORY/${RELATIVE_OUTDIR}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${TMPVAR}") # Per-configuration property (VS, Xcode) FOREACH(CONF ${CMAKE_CONFIGURATION_TYPES}) # For each configuration (Debug, Release, MinSizeRel... and/or anything the user chooses) STRING(TOUPPER "${CONF}" CONF) # Go uppercase (DEBUG, RELEASE...) # We use "FILE(TO_CMAKE_PATH", to create nice looking paths FILE(TO_CMAKE_PATH "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONF}}/${RELATIVE_OUTDIR}" TMPVAR) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES "ARCHIVE_OUTPUT_DIRECTORY_${CONF}" "${TMPVAR}") FILE(TO_CMAKE_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONF}}/${RELATIVE_OUTDIR}" TMPVAR) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES "RUNTIME_OUTPUT_DIRECTORY_${CONF}" "${TMPVAR}") FILE(TO_CMAKE_PATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}}/${RELATIVE_OUTDIR}" TMPVAR) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES "LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${TMPVAR}") ENDFOREACH(CONF ${CMAKE_CONFIGURATION_TYPES}) ENDIF(NOT VALID_BUILDER_VERSION) ENDMACRO(SET_OUTPUT_DIR_PROPERTY_260 TARGET_TARGETNAME RELATIVE_OUTDIR) ####################################################################################################### # macro for common setup of libraries it expect some variables to be set: # either within the local CMakeLists or higher in hierarchy # LIB_NAME is the name of the target library # TARGET_SRC are the sources of the target # TARGET_H are the eventual headers of the target # TARGET_H_NO_MODULE_INSTALL are headers that belong to target but shouldn't get installed by the ModuleInstall script # TARGET_LIBRARIES are the libraries to link to that are internal to the project and have d suffix for debug # TARGET_EXTERNAL_LIBRARIES are external libraries and are not differentiated with d suffix # TARGET_LABEL is the label IDE should show up for targets ########################################################################################################## MACRO(SETUP_LIBRARY LIB_NAME) IF(GLCORE_FOUND) INCLUDE_DIRECTORIES( ${GLCORE_INCLUDE_DIR} ) ENDIF() SET(TARGET_NAME ${LIB_NAME} ) SET(TARGET_TARGETNAME ${LIB_NAME} ) ADD_LIBRARY(${LIB_NAME} ${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC} ${TARGET_H} ${TARGET_H_NO_MODULE_INSTALL} ${TARGET_SRC} ) SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES FOLDER "OSG Core") IF(APPLE) SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES XCODE_ATTRIBUTE_WARNING_CFLAGS "") ENDIF() IF(TARGET_LABEL) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PROJECT_LABEL "${TARGET_LABEL}") ENDIF(TARGET_LABEL) IF(TARGET_LIBRARIES) LINK_INTERNAL(${LIB_NAME} ${TARGET_LIBRARIES}) ENDIF() IF(TARGET_EXTERNAL_LIBRARIES) LINK_EXTERNAL(${LIB_NAME} ${TARGET_EXTERNAL_LIBRARIES}) ENDIF() IF(TARGET_LIBRARIES_VARS) LINK_WITH_VARIABLES(${LIB_NAME} ${TARGET_LIBRARIES_VARS}) ENDIF(TARGET_LIBRARIES_VARS) LINK_CORELIB_DEFAULT(${LIB_NAME}) INCLUDE(ModuleInstall OPTIONAL) ENDMACRO(SETUP_LIBRARY LIB_NAME) MACRO(SETUP_PLUGIN PLUGIN_NAME) IF(GLCORE_FOUND) INCLUDE_DIRECTORIES( ${GLCORE_INCLUDE_DIR} ) ENDIF() SET(TARGET_NAME ${PLUGIN_NAME} ) #MESSAGE("in -->SETUP_PLUGIN<-- ${TARGET_NAME}-->${TARGET_SRC} <--> ${TARGET_H}<--") ## we have set up the target label and targetname by taking into account global prfix (osgdb_) IF(NOT TARGET_TARGETNAME) SET(TARGET_TARGETNAME "${TARGET_DEFAULT_PREFIX}${TARGET_NAME}") ENDIF(NOT TARGET_TARGETNAME) IF(NOT TARGET_LABEL) SET(TARGET_LABEL "${TARGET_DEFAULT_LABEL_PREFIX} ${TARGET_NAME}") ENDIF(NOT TARGET_LABEL) ## plugins gets put in libopenscenegraph by default IF(${ARGC} GREATER 1) SET(PACKAGE_COMPONENT libopenscenegraph-${ARGV1}) ELSE(${ARGC} GREATER 1) SET(PACKAGE_COMPONENT libopenscenegraph) ENDIF(${ARGC} GREATER 1) # Add the VisualStudio versioning info SET(TARGET_SRC ${TARGET_SRC} ${OPENSCENEGRAPH_VERSIONINFO_RC}) # here we use the command to generate the library IF (DYNAMIC_OPENSCENEGRAPH) ADD_LIBRARY(${TARGET_TARGETNAME} MODULE ${TARGET_SRC} ${TARGET_H}) ELSE (DYNAMIC_OPENSCENEGRAPH) ADD_LIBRARY(${TARGET_TARGETNAME} STATIC ${TARGET_SRC} ${TARGET_H}) ENDIF(DYNAMIC_OPENSCENEGRAPH) IF(MSVC) IF(NOT CMAKE24) SET_OUTPUT_DIR_PROPERTY_260(${TARGET_TARGETNAME} "${OSG_PLUGINS}") # Sets the ouput to be /osgPlugin-X.X.X ; also ensures the /Debug /Release are removed ELSE(NOT CMAKE24) IF(OSG_MSVC_VERSIONED_DLL) #this is a hack... the build place is set to lib/ by LIBARARY_OUTPUT_PATH equal to OUTPUT_LIBDIR #the .lib will be crated in ../ so going straight in lib by the IMPORT_PREFIX property #because we want dll placed in OUTPUT_BINDIR ie the bin folder sibling of lib, we can use ../../bin to go there, #it is hardcoded, we should compute OUTPUT_BINDIR position relative to OUTPUT_LIBDIR ... to be implemented #changing bin to something else breaks this hack #the dll are placed in bin/${OSG_PLUGINS} IF(NOT MSVC_IDE) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PREFIX "../bin/${OSG_PLUGINS}/") ELSE(NOT MSVC_IDE) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PREFIX "../../bin/${OSG_PLUGINS}/" IMPORT_PREFIX "../") ENDIF(NOT MSVC_IDE) ELSE(OSG_MSVC_VERSIONED_DLL) #in standard mode (unversioned) the .lib and .dll are placed in lib//${OSG_PLUGINS}. #here the PREFIX property has been used, the same result would be accomplidhe by prepending ${OSG_PLUGINS}/ to OUTPUT_NAME target property SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PREFIX "${OSG_PLUGINS}/") ENDIF(OSG_MSVC_VERSIONED_DLL) ENDIF(NOT CMAKE24) ENDIF(MSVC) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PROJECT_LABEL "${TARGET_LABEL}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES FOLDER "Plugins") IF(APPLE) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES XCODE_ATTRIBUTE_WARNING_CFLAGS "") ENDIF() SETUP_LINK_LIBRARIES() #the installation path are differentiated for win32 that install in bib versus other architecture that install in lib${LIB_POSTFIX}/${OSG_PLUGINS} IF(WIN32) INSTALL(TARGETS ${TARGET_TARGETNAME} RUNTIME DESTINATION bin COMPONENT ${PACKAGE_COMPONENT} ARCHIVE DESTINATION lib/${OSG_PLUGINS} COMPONENT libopenscenegraph-dev LIBRARY DESTINATION bin/${OSG_PLUGINS} COMPONENT ${PACKAGE_COMPONENT}) IF(MSVC AND DYNAMIC_OPENSCENEGRAPH) INSTALL(FILES ${OUTPUT_BINDIR}/${OSG_PLUGINS}/${TARGET_TARGETNAME}${CMAKE_RELWITHDEBINFO_POSTFIX}.pdb DESTINATION bin/${OSG_PLUGINS} COMPONENT ${PACKAGE_COMPONENT} CONFIGURATIONS RelWithDebInfo) INSTALL(FILES ${OUTPUT_BINDIR}/${OSG_PLUGINS}/${TARGET_TARGETNAME}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION bin/${OSG_PLUGINS} COMPONENT ${PACKAGE_COMPONENT} CONFIGURATIONS Debug) ENDIF(MSVC AND DYNAMIC_OPENSCENEGRAPH) ELSE(WIN32) INSTALL(TARGETS ${TARGET_TARGETNAME} RUNTIME DESTINATION bin COMPONENT ${PACKAGE_COMPONENT} ARCHIVE DESTINATION lib${LIB_POSTFIX}/${OSG_PLUGINS} COMPONENT libopenscenegraph-dev LIBRARY DESTINATION lib${LIB_POSTFIX}/${OSG_PLUGINS} COMPONENT ${PACKAGE_COMPONENT}) ENDIF(WIN32) ENDMACRO(SETUP_PLUGIN) ################################################################################################################# # this is the macro for example and application setup ########################################################### MACRO(SETUP_EXE IS_COMMANDLINE_APP) #MESSAGE("in -->SETUP_EXE<-- ${TARGET_NAME}-->${TARGET_SRC} <--> ${TARGET_H}<--") IF(GL3_FOUND) INCLUDE_DIRECTORIES( ${GLCORE_INCLUDE_DIR} ) ENDIF() IF(NOT TARGET_TARGETNAME) SET(TARGET_TARGETNAME "${TARGET_DEFAULT_PREFIX}${TARGET_NAME}") ENDIF(NOT TARGET_TARGETNAME) IF(NOT TARGET_LABEL) SET(TARGET_LABEL "${TARGET_DEFAULT_LABEL_PREFIX} ${TARGET_NAME}") ENDIF(NOT TARGET_LABEL) IF(${IS_COMMANDLINE_APP}) ADD_EXECUTABLE(${TARGET_TARGETNAME} ${TARGET_SRC} ${TARGET_H}) ELSE(${IS_COMMANDLINE_APP}) IF(APPLE) # SET(MACOSX_BUNDLE_LONG_VERSION_STRING "${OPENSCENEGRAPH_MAJOR_VERSION}.${OPENSCENEGRAPH_MINOR_VERSION}.${OPENSCENEGRAPH_PATCH_VERSION}") # Short Version is the "marketing version". It is the version # the user sees in an information panel. SET(MACOSX_BUNDLE_SHORT_VERSION_STRING "${OPENSCENEGRAPH_MAJOR_VERSION}.${OPENSCENEGRAPH_MINOR_VERSION}.${OPENSCENEGRAPH_PATCH_VERSION}") # Bundle version is the version the OS looks at. SET(MACOSX_BUNDLE_BUNDLE_VERSION "${OPENSCENEGRAPH_MAJOR_VERSION}.${OPENSCENEGRAPH_MINOR_VERSION}.${OPENSCENEGRAPH_PATCH_VERSION}") SET(MACOSX_BUNDLE_GUI_IDENTIFIER "org.openscenegraph.${TARGET_TARGETNAME}" ) # replace underscore by hyphen STRING(REGEX REPLACE "_" "-" MACOSX_BUNDLE_GUI_IDENTIFIER ${MACOSX_BUNDLE_GUI_IDENTIFIER}) SET(MACOSX_BUNDLE_BUNDLE_NAME "${TARGET_NAME}" ) # SET(MACOSX_BUNDLE_ICON_FILE "myicon.icns") # SET(MACOSX_BUNDLE_COPYRIGHT "") # SET(MACOSX_BUNDLE_INFO_STRING "Info string, localized?") ENDIF(APPLE) IF(WIN32) IF (REQUIRE_WINMAIN_FLAG) SET(PLATFORM_SPECIFIC_CONTROL WIN32) ENDIF(REQUIRE_WINMAIN_FLAG) ENDIF(WIN32) IF(APPLE) IF(OSG_BUILD_APPLICATION_BUNDLES) SET(PLATFORM_SPECIFIC_CONTROL MACOSX_BUNDLE) ENDIF(OSG_BUILD_APPLICATION_BUNDLES) ENDIF(APPLE) ADD_EXECUTABLE(${TARGET_TARGETNAME} ${PLATFORM_SPECIFIC_CONTROL} ${TARGET_SRC} ${TARGET_H}) ENDIF(${IS_COMMANDLINE_APP}) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES PROJECT_LABEL "${TARGET_LABEL}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME}) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES DEBUG_OUTPUT_NAME "${TARGET_NAME}${CMAKE_DEBUG_POSTFIX}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES RELEASE_OUTPUT_NAME "${TARGET_NAME}${CMAKE_RELEASE_POSTFIX}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES RELWITHDEBINFO_OUTPUT_NAME "${TARGET_NAME}${CMAKE_RELWITHDEBINFO_POSTFIX}") SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES MINSIZEREL_OUTPUT_NAME "${TARGET_NAME}${CMAKE_MINSIZEREL_POSTFIX}") IF(MSVC_IDE AND OSG_MSVC_VERSIONED_DLL) SET_OUTPUT_DIR_PROPERTY_260(${TARGET_TARGETNAME} "") # Ensure the /Debug /Release are removed ENDIF(MSVC_IDE AND OSG_MSVC_VERSIONED_DLL) IF(APPLE) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES XCODE_ATTRIBUTE_WARNING_CFLAGS "") ENDIF() SETUP_LINK_LIBRARIES() ENDMACRO(SETUP_EXE) # Takes optional second argument (is_commandline_app?) in ARGV1 MACRO(SETUP_APPLICATION APPLICATION_NAME) SET(TARGET_NAME ${APPLICATION_NAME} ) IF(${ARGC} GREATER 1) SET(IS_COMMANDLINE_APP ${ARGV1}) ELSE(${ARGC} GREATER 1) SET(IS_COMMANDLINE_APP 0) ENDIF(${ARGC} GREATER 1) SETUP_EXE(${IS_COMMANDLINE_APP}) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES FOLDER "Applications") IF(APPLE) INSTALL(TARGETS ${TARGET_TARGETNAME} RUNTIME DESTINATION bin BUNDLE DESTINATION bin) ELSE(APPLE) INSTALL(TARGETS ${TARGET_TARGETNAME} RUNTIME DESTINATION bin COMPONENT openscenegraph ) IF(MSVC) INSTALL(FILES ${CMAKE_BINARY_DIR}/bin/${TARGET_NAME}${CMAKE_RELWITHDEBINFO_POSTFIX}.pdb DESTINATION bin COMPONENT openscenegraph CONFIGURATIONS RelWithDebInfo) INSTALL(FILES ${CMAKE_BINARY_DIR}/bin/${TARGET_NAME}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION bin COMPONENT openscenegraph CONFIGURATIONS Debug) ENDIF(MSVC) ENDIF(APPLE) ENDMACRO(SETUP_APPLICATION) MACRO(SETUP_COMMANDLINE_APPLICATION APPLICATION_NAME) SETUP_APPLICATION(${APPLICATION_NAME} 1) ENDMACRO(SETUP_COMMANDLINE_APPLICATION) # Takes optional second argument (is_commandline_app?) in ARGV1 MACRO(SETUP_EXAMPLE EXAMPLE_NAME) SET(TARGET_NAME ${EXAMPLE_NAME} ) IF(${ARGC} GREATER 1) SET(IS_COMMANDLINE_APP ${ARGV1}) ELSE(${ARGC} GREATER 1) SET(IS_COMMANDLINE_APP 0) ENDIF(${ARGC} GREATER 1) SETUP_EXE(${IS_COMMANDLINE_APP}) SET_TARGET_PROPERTIES(${TARGET_TARGETNAME} PROPERTIES FOLDER "Examples") IF(APPLE) INSTALL(TARGETS ${TARGET_TARGETNAME} RUNTIME DESTINATION share/OpenSceneGraph/bin BUNDLE DESTINATION share/OpenSceneGraph/bin ) ELSE(APPLE) INSTALL(TARGETS ${TARGET_TARGETNAME} RUNTIME DESTINATION share/OpenSceneGraph/bin COMPONENT openscenegraph-examples ) IF(MSVC) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_TARGETNAME}${CMAKE_RELWITHDEBINFO_POSTFIX}.pdb DESTINATION share/OpenSceneGraph/bin COMPONENT openscenegraph-examples CONFIGURATIONS RelWithDebInfo) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_TARGETNAME}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION share/OpenSceneGraph/bin COMPONENT openscenegraph-examples CONFIGURATIONS Debug) ENDIF(MSVC) ENDIF(APPLE) ENDMACRO(SETUP_EXAMPLE) MACRO(SETUP_COMMANDLINE_EXAMPLE EXAMPLE_NAME) SETUP_EXAMPLE(${EXAMPLE_NAME} 1) ENDMACRO(SETUP_COMMANDLINE_EXAMPLE) # Takes two optional arguments -- osg prefix and osg version MACRO(HANDLE_MSVC_DLL) #this is a hack... the build place is set to lib/ by LIBARARY_OUTPUT_PATH equal to OUTPUT_LIBDIR #the .lib will be crated in ../ so going straight in lib by the IMPORT_PREFIX property #because we want dll placed in OUTPUT_BINDIR ie the bin folder sibling of lib, we can use ../../bin to go there, #it is hardcoded, we should compute OUTPUT_BINDIR position relative to OUTPUT_LIBDIR ... to be implemented #changing bin to something else breaks this hack #the dll are versioned by prefixing the name with osg${OPENSCENEGRAPH_SOVERSION}- # LIB_PREFIX: use "osg" by default, else whatever we've been given. IF(${ARGC} GREATER 0) SET(LIB_PREFIX ${ARGV0}) ELSE(${ARGC} GREATER 0) SET(LIB_PREFIX osg) ENDIF(${ARGC} GREATER 0) # LIB_SOVERSION: use OSG's soversion by default, else whatever we've been given IF(${ARGC} GREATER 1) SET(LIB_SOVERSION ${ARGV1}) ELSE(${ARGC} GREATER 1) SET(LIB_SOVERSION ${OPENSCENEGRAPH_SOVERSION}) ENDIF(${ARGC} GREATER 1) SET_OUTPUT_DIR_PROPERTY_260(${LIB_NAME} "") # Ensure the /Debug /Release are removed IF(NOT MSVC_IDE) IF (NOT CMAKE24) BUILDER_VERSION_GREATER(2 8 0) IF(NOT VALID_BUILDER_VERSION) # If CMake < 2.8.1 SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "../bin/${LIB_PREFIX}${LIB_SOVERSION}-" IMPORT_PREFIX "../") ELSE(NOT VALID_BUILDER_VERSION) SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "${LIB_PREFIX}${LIB_SOVERSION}-") ENDIF(NOT VALID_BUILDER_VERSION) ELSE (NOT CMAKE24) SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "../bin/${LIB_PREFIX}${LIB_SOVERSION}-" IMPORT_PREFIX "../") SET(NEW_LIB_NAME "${OUTPUT_BINDIR}/${LIB_PREFIX}${LIB_SOVERSION}-${LIB_NAME}") ADD_CUSTOM_COMMAND( TARGET ${LIB_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${NEW_LIB_NAME}.lib" "${OUTPUT_LIBDIR}/${LIB_NAME}.lib" COMMAND ${CMAKE_COMMAND} -E copy "${NEW_LIB_NAME}.exp" "${OUTPUT_LIBDIR}/${LIB_NAME}.exp" COMMAND ${CMAKE_COMMAND} -E remove "${NEW_LIB_NAME}.lib" COMMAND ${CMAKE_COMMAND} -E remove "${NEW_LIB_NAME}.exp" ) ENDIF (NOT CMAKE24) ELSE(NOT MSVC_IDE) IF (NOT CMAKE24) BUILDER_VERSION_GREATER(2 8 0) IF(NOT VALID_BUILDER_VERSION) # If CMake < 2.8.1 SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "../../bin/${LIB_PREFIX}${LIB_SOVERSION}-" IMPORT_PREFIX "../") ELSE(NOT VALID_BUILDER_VERSION) SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "${LIB_PREFIX}${LIB_SOVERSION}-") ENDIF(NOT VALID_BUILDER_VERSION) ELSE (NOT CMAKE24) SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "../../bin/${LIB_PREFIX}${LIB_SOVERSION}-" IMPORT_PREFIX "../") ENDIF (NOT CMAKE24) ENDIF(NOT MSVC_IDE) # SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "../../bin/osg${OPENSCENEGRAPH_SOVERSION}-") # SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES IMPORT_PREFIX "../") ENDMACRO(HANDLE_MSVC_DLL) MACRO(REMOVE_CXX_FLAG flag) STRING(REPLACE "${flag}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") ENDMACRO() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindPoppler-glib.cmake0000644000175000017500000000156213151044751025536 0ustar albertoalberto#use pkg-config to find various modues INCLUDE(FindPkgConfig OPTIONAL) IF(PKG_CONFIG_FOUND) INCLUDE(FindPkgConfig) PKG_CHECK_MODULES(CAIRO cairo) PKG_CHECK_MODULES(POPPLER poppler-glib) IF (POPPLER_FOUND) INCLUDE(CheckCXXSourceRuns) SET(CMAKE_REQUIRED_INCLUDES ${POPPLER_INCLUDE_DIRS}) # Do step by step checking, CHECK_CXX_SOURCE_RUNS(" #include #include int main() { #ifdef POPPLER_HAS_CAIRO return EXIT_SUCCESS; #else return EXIT_FAILURE #endif } " POPPLER_HAS_CAIRO) IF (NOT POPPLER_HAS_CAIRO) SET(POPPLER_FOUND FALSE) ENDIF() ENDIF() # IF (POPPLER_FOUND AND (NOT POPPLER_LIBRARIES OR NOT POPPLER_INCLUDE_DIRS) ) # SET(POPPLER_FOUND FALSE) # ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/OsgCPackConfig.cmake.in0000644000175000017500000001021313151044751025557 0ustar albertoalberto# This file will be configured to contain variables for CPack. These variables # should be set in the CMake list file of the project before CPack module is # included. Example variables are: # CPACK_GENERATOR - Generator used to create package # CPACK_INSTALL_CMAKE_PROJECTS - For each project (path, name, component) # CPACK_CMAKE_GENERATOR - CMake Generator used for the projects # CPACK_INSTALL_COMMANDS - Extra commands to install components # CPACK_INSTALL_DIRECTORIES - Extra directories to install # CPACK_PACKAGE_DESCRIPTION_FILE - Description file for the package # CPACK_PACKAGE_DESCRIPTION_SUMMARY - Summary of the package # CPACK_PACKAGE_EXECUTABLES - List of pairs of executables and labels # CPACK_PACKAGE_FILE_NAME - Name of the package generated # CPACK_PACKAGE_ICON - Icon used for the package # CPACK_PACKAGE_INSTALL_DIRECTORY - Name of directory for the installer # CPACK_PACKAGE_NAME - Package project name # CPACK_PACKAGE_VENDOR - Package project vendor # CPACK_PACKAGE_VERSION - Package project version # CPACK_PACKAGE_VERSION_MAJOR - Package project version (major) # CPACK_PACKAGE_VERSION_MINOR - Package project version (minor) # CPACK_PACKAGE_VERSION_PATCH - Package project version (patch) # There are certain generator specific ones # NSIS Generator: # CPACK_PACKAGE_INSTALL_REGISTRY_KEY - Name of the registry key for the installer # CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS - Extra commands used during uninstall # CPACK_NSIS_EXTRA_INSTALL_COMMANDS - Extra commands used during install SET(CPACK_BINARY_BUNDLE "${CPACK_BINARY_BUNDLE}") SET(CPACK_BINARY_CYGWIN "${CPACK_BINARY_CYGWIN}") SET(CPACK_BINARY_DEB "${CPACK_BINARY_DEB}") SET(CPACK_BINARY_NSIS "${CPACK_BINARY_NSIS}") SET(CPACK_BINARY_OSXX11 "${CPACK_BINARY_OSXX11}") SET(CPACK_BINARY_PACKAGEMAKER "${CPACK_BINARY_PACKAGEMAKER}") SET(CPACK_BINARY_RPM "${CPACK_BINARY_RPM}") SET(CPACK_BINARY_STGZ "${CPACK_BINARY_STGZ}") SET(CPACK_BINARY_TBZ2 "${CPACK_BINARY_TBZ2}") SET(CPACK_BINARY_TGZ "${CPACK_BINARY_TGZ}") SET(CPACK_BINARY_TZ "${CPACK_BINARY_TZ}") SET(CPACK_BINARY_ZIP "${CPACK_BINARY_ZIP}") SET(CPACK_CMAKE_GENERATOR "${CMAKE_GENERATOR}") SET(CPACK_COMPONENTS_ALL "${CPACK_COMPONENTS_ALL}") SET(CPACK_COMPONENT_UNSPECIFIED_HIDDEN "TRUE") SET(CPACK_COMPONENT_UNSPECIFIED_REQUIRED "TRUE") SET(CPACK_GENERATOR "${CPACK_GENERATOR}") SET(CPACK_INSTALL_CMAKE_PROJECTS "${OpenSceneGraph_BINARY_DIR};OpenSceneGraph;${OSG_CPACK_COMPONENT};/") SET(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") SET(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") SET(CPACK_MODULE_PATH "${OpenSceneGraph_SOURCE_DIR}/CMakeModules;") SET(CPACK_NSIS_DISPLAY_NAME "${CMAKE_PROJECT_NAME} ${OPENSCENEGRAPH_VERSION}") SET(CPACK_NSIS_INSTALLER_ICON_CODE "") SET(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") SET(CPACK_OUTPUT_CONFIG_FILE "${PROJECT_BINARY_DIR}/CPackConfig-${OSG_CPACK_COMPONENT}.cmake") SET(CPACK_PACKAGE_DEFAULT_LOCATION "/") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenSceneGraph_SOURCE_DIR}/README.txt") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The OpenSceneGraph is an open source high performance 3d graphics toolkit") SET(CPACK_PACKAGE_FILE_NAME "${OSG_PACKAGE_FILE_NAME}") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_INSTALL_DIRECTORY}") SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CMAKE_PROJECT_NAME}-${OPENSCENEGRAPH_VERSION}") SET(CPACK_PACKAGE_NAME "${CPACK_PACKAGE_NAME}") SET(CPACK_PACKAGE_RELOCATABLE "true") SET(CPACK_PACKAGE_VENDOR "The OpenSceneGraph developers and contributors lead by Robert Osfield") SET(CPACK_PACKAGE_VERSION "${OPENSCENEGRAPH_VERSION}") SET(CPACK_PACKAGE_VERSION_MAJOR "${OPENSCENEGRAPH_MAJOR_VERSION}") SET(CPACK_PACKAGE_VERSION_MINOR "${OPENSCENEGRAPH_MINOR_VERSION}") SET(CPACK_PACKAGE_VERSION_PATCH "${OPENSCENEGRAPH_PATCH_VERSION}") SET(CPACK_RESOURCE_FILE_LICENSE "${OpenSceneGraph_SOURCE_DIR}/LICENSE.txt") SET(CPACK_RESOURCE_FILE_README "${OpenSceneGraph_SOURCE_DIR}/README.txt") SET(CPACK_RESOURCE_FILE_WELCOME "${OpenSceneGraph_SOURCE_DIR}/NEWS.txt") SET(CPACK_STRIP_FILES "ON") OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/CheckAtomicOps.cmake0000644000175000017500000001124313151044751025232 0ustar albertoalberto# Check for availability of atomic operations # This module defines # OPENTHREADS_HAVE_ATOMIC_OPS OPTION(OPENTHREADS_ATOMIC_USE_MUTEX "Set to ON to force OpenThreads to use a mutex for Atmoic." OFF) IF (OPENTHREADS_ATOMIC_USE_MUTEX) SET(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS 0) SET(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS 0) SET(_OPENTHREADS_ATOMIC_USE_SUN 0) SET(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED 0) SET(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC 0) SET(_OPENTHREADS_ATOMIC_USE_MUTEX 1) ELSE() # as the test does not work for IOS hardcode the ATOMIC implementation IF(OSG_BUILD_PLATFORM_IPHONE_SIMULATOR OR OSG_BUILD_PLATFORM_IPHONE) SET(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS 0) SET(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS 0) SET(_OPENTHREADS_ATOMIC_USE_SUN 0) SET(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED 0) SET(_OPENTHREADS_ATOMIC_USE_MUTEX 0) SET(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC 1) ELSE() INCLUDE(CheckCXXSourceRuns) # Do step by step checking, CHECK_CXX_SOURCE_RUNS(" #include int main() { unsigned value = 0; void* ptr = &value; __sync_add_and_fetch(&value, 1); __sync_synchronize(); __sync_sub_and_fetch(&value, 1); if (!__sync_bool_compare_and_swap(&value, 0, 1)) return EXIT_FAILURE; if (!__sync_bool_compare_and_swap(&ptr, ptr, ptr)) return EXIT_FAILURE; return EXIT_SUCCESS; } " _OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) CHECK_CXX_SOURCE_RUNS(" #include int main(int, const char**) { unsigned value = 0; void* ptr = &value; __add_and_fetch(&value, 1); __synchronize(value); __sub_and_fetch(&value, 1); if (!__compare_and_swap(&value, 0, 1)) return EXIT_FAILURE; if (!__compare_and_swap((unsigned long*)&ptr, (unsigned long)ptr, (unsigned long)ptr)) return EXIT_FAILURE; return EXIT_SUCCESS; } " _OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) CHECK_CXX_SOURCE_RUNS(" #include #include int main(int, const char**) { uint_t value = 0; void* ptr = &value; atomic_inc_uint_nv(&value); membar_consumer(); atomic_dec_uint_nv(&value); if (0 != atomic_cas_uint(&value, 0, 1)) return EXIT_FAILURE; if (ptr != atomic_cas_ptr(&ptr, ptr, ptr)) return EXIT_FAILURE; return EXIT_SUCCESS; } " _OPENTHREADS_ATOMIC_USE_SUN) CHECK_CXX_SOURCE_RUNS(" #include #include #include #pragma intrinsic(_InterlockedAnd) #pragma intrinsic(_InterlockedOr) #pragma intrinsic(_InterlockedXor) int main(int, const char**) { volatile long value = 0; long data = 0; long* volatile ptr = &data; InterlockedIncrement(&value); MemoryBarrier(); InterlockedDecrement(&value); if (0 != InterlockedCompareExchange(&value, 1, 0)) return EXIT_FAILURE; if (ptr != InterlockedCompareExchangePointer((PVOID volatile*)&ptr, (PVOID)ptr, (PVOID)ptr)) return EXIT_FAILURE; return EXIT_SUCCESS; } " _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED) CHECK_CXX_SOURCE_RUNS(" #include int main() { volatile int32_t value = 0; long data = 0; long * volatile ptr = &data; OSAtomicIncrement32(&value); OSMemoryBarrier(); OSAtomicDecrement32(&value); OSAtomicCompareAndSwapInt(value, 1, &value); OSAtomicCompareAndSwapPtr(ptr, ptr, (void * volatile *)&ptr); } " _OPENTHREADS_ATOMIC_USE_BSD_ATOMIC) IF(NOT _OPENTHREADS_ATOMIC_USE_GCC_BUILTINS AND NOT _OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS AND NOT _OPENTHREADS_ATOMIC_USE_SUN AND NOT _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED AND NOT _OPENTHREADS_ATOMIC_USE_BSD_ATOMIC) SET(_OPENTHREADS_ATOMIC_USE_MUTEX 1) ENDIF() # MinGW can set both WIN32_INTERLOCKED and GCC_BUILTINS to true which results in compliation errors IF (_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS AND _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED) # In this case we prefer the GCC_BUILTINS SET(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS 1) SET(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED 0) ENDIF() ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindCoreVideo.cmake0000644000175000017500000000124313151044751025055 0ustar albertoalberto# Locate Apple CoreVideo (next-generation QuickTime) # This module defines # COREVIDEO_LIBRARY # COREVIDEO_FOUND, if false, do not try to link to gdal # COREVIDEO_INCLUDE_DIR, where to find the headers # # $COREVIDEO_DIR is an environment variable that would # correspond to the ./configure --prefix=$COREVIDEO_DIR # # Created by Eric Wing. # CoreVideo on OS X looks different than CoreVideo for Windows, # so I am going to case the two. IF(APPLE) FIND_PATH(COREVIDEO_INCLUDE_DIR CoreVideo/CoreVideo.h) FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo) ENDIF() SET(COREVIDEO_FOUND "NO") IF(COREVIDEO_LIBRARY AND COREVIDEO_INCLUDE_DIR) SET(COREVIDEO_FOUND "YES") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindCoreMedia.cmake0000644000175000017500000000106513151044751025030 0ustar albertoalberto# Locate Apple CoreMedia # This module defines # COREMEDIA_LIBRARY # COREMEDIA_FOUND, if false, do not try to link to gdal # COREMEDIA_INCLUDE_DIR, where to find the headers # # $COREMEDIA_DIR is an environment variable that would # correspond to the ./configure --prefix=$COREMEDIA_DIR # # Created by Stephan Maximilian Huber. IF(APPLE) FIND_PATH(COREMEDIA_INCLUDE_DIR CoreMedia/CoreMedia.h) FIND_LIBRARY(COREMEDIA_LIBRARY CoreMedia) ENDIF() SET(COREMEDIA_FOUND "NO") IF(COREMEDIA_LIBRARY AND COREMEDIA_INCLUDE_DIR) SET(COREMEDIA_FOUND "YES") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindQTKit.cmake0000644000175000017500000000307113151044751024173 0ustar albertoalberto# Locate Apple QTKit (next-generation QuickTime) # This module defines # QTKIT_LIBRARY # QTKIT_FOUND, if false, do not try to link to gdal # QTKIT_INCLUDE_DIR, where to find the headers # # $QTKIT_DIR is an environment variable that would # correspond to the ./configure --prefix=$QTKIT_DIR # # Created by Eric Wing. # QTKit on OS X looks different than QTKit for Windows, # so I am going to case the two. IF(APPLE) FIND_PATH(QTKIT_INCLUDE_DIR QTKit/QTKit.h) FIND_LIBRARY(QTKIT_LIBRARY QTKit) ENDIF() SET(QTKIT_FOUND "NO") IF(QTKIT_LIBRARY AND QTKIT_INCLUDE_DIR) SET(QTKIT_FOUND "YES") ENDIF() IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) SET(QTKIT_FOUND "NO") ENDIF() IF(APPLE) # Technically QTKit is 64-bit capable, but the QTKit plug-in currently uses # a few 32-bit only APIs to bridge QTKit and Core Video. # As such, the plugin won't compile for 64-bit until Apple fixes this hole # in their API. # For simplicitly, I pretend QTKit is only 32-bit, but if/when Apple fixes # this, we need an OS version check. # Snow Leopard still lacks a 64-bit path for this. #First check to see if we are running with a native 64-bit compiler (10.6 default) and implicit arch IF(NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SIZEOF_VOID_P EQUAL 8) SET(QTKIT_FOUND "NO") ELSE() #Otherwise check to see if 64-bit is explicitly called for. LIST(FIND CMAKE_OSX_ARCHITECTURES "x86_64" has64Compile) IF(NOT has64Compile EQUAL -1) SET(QTKIT_FOUND "NO") ENDIF() ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/cmake_uninstall.cmake.in0000644000175000017500000000212213151044751026150 0ustar albertoalbertoIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF() FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"${file}\"") IF(EXISTS "${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") ENDIF() ELSEIF(IS_SYMLINK "${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") ENDIF() ELSE() MESSAGE(STATUS "File \"${file}\" does not exist.") ENDIF() ENDFOREACH() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindOpenThreads.cmake0000644000175000017500000001356313151044751025422 0ustar albertoalberto# OpenThreads is a C++ based threading library. Its largest userbase # seems to OpenSceneGraph so you might notice I accept OSGDIR as an # environment path. # I consider this part of the Findosg* suite used to find OpenSceneGraph # components. # Each component is separate and you must opt in to each module. # # Locate OpenThreads # This module defines # OPENTHREADS_LIBRARY # OPENTHREADS_FOUND, if false, do not try to link to OpenThreads # OPENTHREADS_INCLUDE_DIR, where to find the headers # # $OPENTHREADS_DIR is an environment variable that would # correspond to the ./configure --prefix=$OPENTHREADS_DIR # used in building osg. # # Created by Eric Wing. # prefer FindOpenThreads from cmake distribution if(EXISTS ${CMAKE_ROOT}/Modules/FindOpenThreads.cmake) include(${CMAKE_ROOT}/Modules/FindOpenThreads.cmake) if(OPENTHREADS_FOUND) return() endif() endif() # Header files are presumed to be included like # #include # To make it easier for one-step automated configuration/builds, # we leverage environmental paths. This is preferable # to the -DVAR=value switches because it insulates the # users from changes we may make in this script. # It also offers a little more flexibility than setting # the CMAKE_*_PATH since we can target specific components. # However, the default CMake behavior will search system paths # before anything else. This is problematic in the cases # where you have an older (stable) version installed, but # are trying to build a newer version. # CMake doesn't offer a nice way to globally control this behavior # so we have to do a nasty "double FIND_" in this module. # The first FIND disables the CMAKE_ search paths and only checks # the environmental paths. # If nothing is found, then the second find will search the # standard install paths. # Explicit -DVAR=value arguments should still be able to override everything. # Note: We have added an additional check for ${CMAKE_PREFIX_PATH}. # This is not an official CMake variable, but one we are proposing be # added to CMake. Be warned that this may go away or the variable name # may change. FIND_PATH(OPENTHREADS_INCLUDE_DIR OpenThreads/Thread PATHS $ENV{OPENTHREADS_INCLUDE_DIR} $ENV{OPENTHREADS_DIR}/include $ENV{OPENTHREADS_DIR} $ENV{OSG_INCLUDE_DIR} $ENV{OSG_DIR}/include $ENV{OSG_DIR} $ENV{OSGDIR}/include $ENV{OSGDIR} NO_DEFAULT_PATH ) FIND_PATH(OPENTHREADS_INCLUDE_DIR OpenThreads/Thread PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(OPENTHREADS_INCLUDE_DIR OpenThreads/Thread ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]/include [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include ) FIND_LIBRARY(OPENTHREADS_LIBRARY NAMES OpenThreads OpenThreadsWin32 PATHS $ENV{OPENTHREADS_LIBRARY_DIR} $ENV{OPENTHREADS_DIR}/lib64 $ENV{OPENTHREADS_DIR}/lib $ENV{OPENTHREADS_DIR} $ENV{OSG_LIBRARY_DIR} $ENV{OSG_DIR}/lib64 $ENV{OSG_DIR}/lib $ENV{OSG_DIR} $ENV{OSGDIR}/lib64 $ENV{OSGDIR}/lib $ENV{OSGDIR} NO_DEFAULT_PATH ) FIND_LIBRARY(OPENTHREADS_LIBRARY NAMES OpenThreads OpenThreadsWin32 PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(OPENTHREADS_LIBRARY NAMES OpenThreads OpenThreadsWin32 PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib /sw/lib64 /sw/lib /opt/local/lib64 /opt/local/lib /opt/csw/lib64 /opt/csw/lib /opt/lib64 /opt/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/lib ) FIND_LIBRARY(OPENTHREADS_LIBRARY_DEBUG NAMES OpenThreadsd OpenThreadsWin32d PATHS $ENV{OPENTHREADS_DEBUG_LIBRARY_DIR} $ENV{OPENTHREADS_LIBRARY_DIR} $ENV{OPENTHREADS_DIR}/lib64 $ENV{OPENTHREADS_DIR}/lib $ENV{OPENTHREADS_DIR} $ENV{OSG_LIBRARY_DIR} $ENV{OSG_DIR}/lib64 $ENV{OSG_DIR}/lib $ENV{OSG_DIR} $ENV{OSGDIR}/lib64 $ENV{OSGDIR}/lib $ENV{OSGDIR} NO_DEFAULT_PATH ) FIND_LIBRARY(OPENTHREADS_LIBRARY_DEBUG NAMES OpenThreadsd OpenThreadsWin32d PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(OPENTHREADS_LIBRARY_DEBUG NAMES OpenThreadsd OpenThreadsWin32d PATHS /usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib /sw/lib64 /sw/lib /opt/local/lib64 /opt/local/lib /opt/csw/lib64 /opt/csw/lib /opt/lib64 /opt/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/lib ) IF(OPENTHREADS_LIBRARY) IF(NOT OPENTHREADS_LIBRARY_DEBUG) #MESSAGE("-- Warning Debug OpenThreads not found, using: ${OPENTHREADS_LIBRARY}") #SET(OPENTHREADS_LIBRARY_DEBUG "${OPENTHREADS_LIBRARY}") SET(OPENTHREADS_LIBRARY_DEBUG "${OPENTHREADS_LIBRARY}" CACHE FILEPATH "Debug version of OpenThreads Library (use regular version if not available)" FORCE) ENDIF(NOT OPENTHREADS_LIBRARY_DEBUG) ENDIF(OPENTHREADS_LIBRARY) SET(OPENTHREADS_FOUND "NO") IF(OPENTHREADS_INCLUDE_DIR AND OPENTHREADS_LIBRARY) SET(OPENTHREADS_FOUND "YES") # MESSAGE("-- Found OpenThreads: "${OPENTHREADS_LIBRARY}) ENDIF(OPENTHREADS_INCLUDE_DIR AND OPENTHREADS_LIBRARY) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGtkGl.cmake0000644000175000017500000000046313151044751024211 0ustar albertoalberto#use pkg-config to find various modues INCLUDE(FindPkgConfig OPTIONAL) IF(PKG_CONFIG_FOUND) INCLUDE(FindPkgConfig) PKG_CHECK_MODULES(GTK gtk+-2.0) IF(WIN32) PKG_CHECK_MODULES(GTKGL gtkglext-win32-1.0) ELSE() PKG_CHECK_MODULES(GTKGL gtkglext-x11-1.0) ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindFLTK.cmake0000644000175000017500000000262613151044751023744 0ustar albertoalberto# Locate FLTK # This module defines # FLTK_LIBRARY # FLTK_FOUND, if false, do not try to link to gdal # FLTK_INCLUDE_DIR, where to find the headers # # $FLTK_DIR is an environment variable that would # correspond to the ./configure --prefix=$FLTK_DIR # # Created by Robert Osfield. # prefer FindFLTK from cmake distribution if(EXISTS ${CMAKE_ROOT}/Modules/FindFLTK.cmake) include(${CMAKE_ROOT}/Modules/FindFLTK.cmake) if(FLTK_FOUND) return() endif() endif() FIND_PATH(FLTK_INCLUDE_DIR Fl/Fl.H Fl/Fl.h $ENV{FLTK_DIR}/include $ENV{FLTK_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) MACRO(FIND_FLTK_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_LIBRARY(${MYLIBRARY} NAMES ${MYLIBRARYNAME} PATHS $ENV{FLTK_DIR}/lib $ENV{FLTK_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) ENDMACRO(FIND_FLTK_LIBRARY LIBRARY LIBRARYNAME) FIND_FLTK_LIBRARY(FLTK_LIBRARY fltk) FIND_FLTK_LIBRARY(FLTK_GL_LIBRARY fltk_gl) SET(FLTK_FOUND "NO") IF(FLTK_LIBRARY AND FLTK_INCLUDE_DIR) SET(FLTK_FOUND "YES") ENDIF(FLTK_LIBRARY AND FLTK_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/ListHandle.cmake0000644000175000017500000000626413151044751024434 0ustar albertoalberto#miscellaneous macros ################### macros from http://www.cmake.org/Wiki/CMakeMacroListOperations MACRO(CAR var) SET(${var} ${ARGV1}) ENDMACRO(CAR) MACRO(CDR var junk) SET(${var} ${ARGN}) ENDMACRO(CDR) MACRO(LIST_INDEX var index) SET(list . ${ARGN}) FOREACH(i RANGE 1 ${index}) CDR(list ${list}) ENDFOREACH(i) CAR(${var} ${list}) ENDMACRO(LIST_INDEX) ######### LIST_CONTAINS usage #SET(MYLIST hello world foo bar) #LIST_CONTAINS(contains foo ${MYLIST}) #IF (contains) # MESSAGE("MYLIST contains foo") #ENDIF (contains) #LIST_CONTAINS(contains baz ${MYLIST}) #IF (NOT contains) # MESSAGE("MYLIST does not contain baz") #ENDIF (NOT contains) MACRO(LIST_CONTAINS var value) SET(${var}) FOREACH (value2 ${ARGN}) IF (${value} STREQUAL ${value2}) SET(${var} TRUE) ENDIF (${value} STREQUAL ${value2}) ENDFOREACH (value2) ENDMACRO(LIST_CONTAINS) ############################################################ ################### macros from http://www.cmake.org/Wiki/CMakeMacroParseArguments MACRO(PARSE_ARGUMENTS prefix arg_names option_names) #MESSAGE("!!!! ${prefix} args-->${arg_names}<-- opt-->${option_names}<--") SET(DEFAULT_ARGS) FOREACH(arg_name ${arg_names}) SET(${prefix}_${arg_name}) ENDFOREACH(arg_name) FOREACH(option ${option_names}) SET(${prefix}_${option} FALSE) ENDFOREACH(option) SET(current_arg_name DEFAULT_ARGS) SET(current_arg_list) FOREACH(arg ${ARGN}) #debug#MESSAGE("---->${arg}<------") LIST_CONTAINS(is_arg_name ${arg} ${arg_names}) IF (is_arg_name) SET(${prefix}_${current_arg_name} ${current_arg_list}) SET(current_arg_name ${arg}) SET(current_arg_list) ELSE (is_arg_name) LIST_CONTAINS(is_option ${arg} ${option_names}) IF (is_option) SET(${prefix}_${arg} TRUE) ELSE (is_option) SET(current_arg_list ${current_arg_list} ${arg}) ENDIF (is_option) ENDIF (is_arg_name) ENDFOREACH(arg) SET(${prefix}_${current_arg_name} ${current_arg_list}) ENDMACRO(PARSE_ARGUMENTS) ############################################################# #MACRO(SHOW_USAGE_OF_PARSE_ARGUMENTS) # PARSE_ARGUMENTS(PLUGIN # "EXPORTS;AUTOLOAD_SCRIPTS;LINK_LIBRARIES;DEPENDS" # "AUTO_INSTALL;NO_MODULE" # ${ARGN} # ) # CAR(PLUGIN_NAME ${PLUGIN_DEFAULT_ARGS}) # CDR(PLUGIN_SOURCES ${PLUGIN_DEFAULT_ARGS}) # # MESSAGE("*** Arguments for ${PLUGIN_NAME}") # MESSAGE("Sources: ${PLUGIN_SOURCES}") # MESSAGE("Exports: ${PLUGIN_EXPORTS}") # MESSAGE("Autoload scripts: ${PLUGIN_AUTOLOAD_SCRIPTS}") # MESSAGE("Link libraries: ${PLUGIN_LINK_LIBRARIES}") # MESSAGE("Depends: ${PLUGIN_DEPENDS}") # IF (PLUGIN_AUTO_INSTALL) # MESSAGE("Auto install") # ENDIF (PLUGIN_AUTO_INSTALL) # IF (PLUGIN_NO_MODULE) # MESSAGE("No module") # ENDIF (PLUGIN_NO_MODULE) #ENDMACRO(SHOW_USAGE_OF_PARSE_ARGUMENTS) #examples #SHOW_USAGE_OF_PARSE_ARGUMENTS(MyAppCore NO_MODULE CoreSource1.cxx CoreSource2.cxx EXPORTS RequiredObject1 RequredObject2 AUTOLOAD_SCRIPTS startup.py initialize.py) #SHOW_USAGE_OF_PARSE_ARGUMENTS(MyAppDefaultComponents # Component1.cxx Component2.cxx # EXPORTS Component1 Component2 # DEPENDS MyAppCore # AUTO_INSTALL # ) ######################################################## OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindFFmpeg.cmake0000644000175000017500000001243013151044751024342 0ustar albertoalberto# Locate ffmpeg # This module defines # FFMPEG_LIBRARIES # FFMPEG_FOUND, if false, do not try to link to ffmpeg # FFMPEG_INCLUDE_DIR, where to find the headers # # $FFMPEG_DIR is an environment variable that would # correspond to the ./configure --prefix=$FFMPEG_DIR # # Created by Robert Osfield. #In ffmpeg code, old version use "#include " and newer use "#include " #In OSG ffmpeg plugin, we used "#include " for compatibility with old version of ffmpeg #With the new version of FFmpeg, a file named "time.h" was added that breaks compatability with the old version of ffmpeg. #We have to search the path which contain the header.h (useful for old version) #and search the path which contain the libname/header.h (useful for new version) #Then we need to include ${FFMPEG_libname_INCLUDE_DIRS} (in old version case, use by ffmpeg header and osg plugin code) # (in new version case, use by ffmpeg header) #and ${FFMPEG_libname_INCLUDE_DIRS/libname} (in new version case, use by osg plugin code) # Macro to find header and lib directories # example: FFMPEG_FIND(AVFORMAT avformat avformat.h) MACRO(FFMPEG_FIND varname shortname headername) # old version of ffmpeg put header in $prefix/include/[ffmpeg] # so try to find header in include directory FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS lib${shortname}/${headername} PATHS ${FFMPEG_ROOT}/include $ENV{FFMPEG_DIR}/include ${FFMPEG_ROOT} $ENV{FFMPEG_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include PATH_SUFFIXES ffmpeg DOC "Location of FFMPEG Headers" ) FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS ${headername} PATHS ${FFMPEG_ROOT}/include $ENV{FFMPEG_DIR}/include ${FFMPEG_ROOT} $ENV{FFMPEG_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include PATH_SUFFIXES ffmpeg DOC "Location of FFMPEG Headers" ) FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES NAMES ${shortname} PATHS ${FFMPEG_ROOT}/lib $ENV{FFMPEG_DIR}/lib ${FFMPEG_ROOT}/lib${shortname} $ENV{FFMPEG_DIR}/lib${shortname} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 DOC "Location of FFMPEG Libraries" ) IF (FFMPEG_${varname}_LIBRARIES AND FFMPEG_${varname}_INCLUDE_DIRS) SET(FFMPEG_${varname}_FOUND 1) ENDIF(FFMPEG_${varname}_LIBRARIES AND FFMPEG_${varname}_INCLUDE_DIRS) ENDMACRO(FFMPEG_FIND) SET(FFMPEG_ROOT "$ENV{FFMPEG_DIR}" CACHE PATH "Location of FFMPEG") # find stdint.h IF(WIN32) FIND_PATH(FFMPEG_STDINT_INCLUDE_DIR stdint.h PATHS ${FFMPEG_ROOT}/include $ENV{FFMPEG_DIR}/include ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include PATH_SUFFIXES ffmpeg DOC "Location of FFMPEG stdint.h Header" ) IF (FFMPEG_STDINT_INCLUDE_DIR) SET(STDINT_OK TRUE) ENDIF() ELSE() SET(STDINT_OK TRUE) ENDIF() FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) FFMPEG_FIND(LIBAVUTIL avutil avutil.h) FFMPEG_FIND(LIBSWRESAMPLE swresample swresample.h) FFMPEG_FIND(LIBAVRESAMPLE avresample avresample.h) FFMPEG_FIND(LIBSWSCALE swscale swscale.h) # not sure about the header to look for here. SET(FFMPEG_FOUND "NO") # Note we don't check FFMPEG_LIBSWSCALE_FOUND here, it's optional. IF (FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND AND STDINT_OK AND ( FFMPEG_LIBSWRESAMPLE_FOUND OR FFMPEG_LIBAVRESAMPLE_FOUND ) ) SET(FFMPEG_FOUND "YES") SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} ${FFMPEG_LIBAVDEVICE_INCLUDE_DIRS} ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} ) # Using the new include style for FFmpeg prevents issues with #include IF (FFMPEG_STDINT_INCLUDE_DIR) SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} ${FFMPEG_STDINT_INCLUDE_DIR} ) ENDIF() SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) # Note we don't add FFMPEG_LIBSWSCALE_LIBRARIES here, it will be added if found later. SET(FFMPEG_LIBRARIES ${FFMPEG_LIBAVFORMAT_LIBRARIES} ${FFMPEG_LIBAVDEVICE_LIBRARIES} ${FFMPEG_LIBAVCODEC_LIBRARIES} ${FFMPEG_LIBAVUTIL_LIBRARIES}) ELSE () # MESSAGE(STATUS "Could not find FFMPEG") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/ModuleInstall.cmake0000644000175000017500000000346313151044751025157 0ustar albertoalberto# INSTALL and SOURCE_GROUP commands for OSG/OT/Producer Modules # Required Vars: # ${LIB_NAME} # ${TARGET_H} SET(INSTALL_INCDIR include) SET(INSTALL_BINDIR bin) IF(WIN32) SET(INSTALL_LIBDIR bin) SET(INSTALL_ARCHIVEDIR lib) ELSE() SET(INSTALL_LIBDIR lib${LIB_POSTFIX}) SET(INSTALL_ARCHIVEDIR lib${LIB_POSTFIX}) ENDIF() SET(HEADERS_GROUP "Header Files") SOURCE_GROUP( ${HEADERS_GROUP} FILES ${TARGET_H} ) IF(MSVC AND OSG_MSVC_VERSIONED_DLL) HANDLE_MSVC_DLL() ENDIF() INSTALL( TARGETS ${LIB_NAME} RUNTIME DESTINATION ${INSTALL_BINDIR} COMPONENT libopenscenegraph LIBRARY DESTINATION ${INSTALL_LIBDIR} COMPONENT libopenscenegraph ARCHIVE DESTINATION ${INSTALL_ARCHIVEDIR} COMPONENT libopenscenegraph-dev ) IF(MSVC AND DYNAMIC_OPENSCENEGRAPH) GET_TARGET_PROPERTY(PREFIX ${LIB_NAME} PREFIX) INSTALL(FILES ${OUTPUT_BINDIR}/${PREFIX}${LIB_NAME}${CMAKE_RELWITHDEBINFO_POSTFIX}.pdb DESTINATION ${INSTALL_BINDIR} COMPONENT libopenscenegraph CONFIGURATIONS RelWithDebInfo) INSTALL(FILES ${OUTPUT_BINDIR}/${PREFIX}${LIB_NAME}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION ${INSTALL_BINDIR} COMPONENT libopenscenegraph CONFIGURATIONS Debug) ENDIF(MSVC AND DYNAMIC_OPENSCENEGRAPH) IF(NOT OSG_COMPILE_FRAMEWORKS) INSTALL ( FILES ${TARGET_H} DESTINATION ${INSTALL_INCDIR}/${LIB_NAME} COMPONENT libopenscenegraph-dev ) ELSE() SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) SET(CMAKE_INSTALL_RPATH "${OSG_COMPILE_FRAMEWORKS_INSTALL_NAME_DIR}") SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION ${OPENSCENEGRAPH_SOVERSION} PUBLIC_HEADER "${TARGET_H}" INSTALL_NAME_DIR "${OSG_COMPILE_FRAMEWORKS_INSTALL_NAME_DIR}" ) # MESSAGE("${OSG_COMPILE_FRAMEWORKS_INSTALL_NAME_DIR}") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindPerformer.cmake0000644000175000017500000000323413151044751025141 0ustar albertoalberto# Locate Performer # This module defines # PERFORMER_LIBRARY # PERFORMER_FOUND, if false, do not try to link to gdal # PERFORMER_INCLUDE_DIR, where to find the headers # # $PERFORMER_DIR is an environment variable that would # correspond to the ./configure --prefix=$PERFORMER_DIR # # Created by Robert Osfield. FIND_PATH(PERFORMER_INCLUDE_DIR Performer/pfdu.h $ENV{PFROOT}/include $ENV{PFROOT} $ENV{PERFORMER_DIR}/include $ENV{PERFORMER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) IF(MSVC) FIND_LIBRARY(PERFORMER_LIBRARY NAMES libpf PATHS $ENV{PFROOT}/lib $ENV{PFROOT} $ENV{PERFORMER_DIR}/lib $ENV{PERFORMER_DIR} $ENV{OSGDIR}/lib $ENV{OSGDIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) ELSE(MSVC) FIND_LIBRARY(PERFORMER_LIBRARY NAMES pf PATHS $ENV{PFROOT}/lib $ENV{PFROOT} $ENV{PERFORMER_DIR}/lib $ENV{PERFORMER_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) ENDIF(MSVC) SET(PERFORMER_FOUND "NO") IF(PERFORMER_LIBRARY AND PERFORMER_INCLUDE_DIR) SET(PERFORMER_FOUND "YES") ENDIF(PERFORMER_LIBRARY AND PERFORMER_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindLIBLAS.cmake0000644000175000017500000000513313151044751024146 0ustar albertoalberto#--- # File: FindLIBLAS.cmake # # Find the native LIBLAS includes and library # # LIBLAS_INCLUDE_DIRS - where to find liblas's includes. # LIBLAS_LIBRARIES - List of libraries when using liblas. # LIBLAS_FOUND - True if liblas found. #--- # Set the include dir: find_path(LIBLAS_INCLUDE_DIR liblas/liblas.hpp) # Macro for setting libraries: macro(FIND_LIBLAS_LIBRARY MYLIBRARY MYLIBRARYNAME) find_library( "${MYLIBRARY}_DEBUG" NAMES "${MYLIBRARYNAME}${CMAKE_DEBUG_POSTFIX}" PATHS ${LIBLAS_DIR}/lib/Debug ${LIBLAS_DIR}/lib64/Debug ${LIBLAS_DIR}/lib ${LIBLAS_DIR}/lib64 $ENV{LIBLAS_DIR}/lib/debug $ENV{LIBLAS_DIR}/lib64/debug NO_DEFAULT_PATH ) find_library( "${MYLIBRARY}_DEBUG" NAMES "${MYLIBRARYNAME}${CMAKE_DEBUG_POSTFIX}" PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;LIBLAS_ROOT]/lib /usr/freeware/lib64 ) find_library( ${MYLIBRARY} NAMES "${MYLIBRARYNAME}${CMAKE_RELEASE_POSTFIX}" PATHS ${LIBLAS_DIR}/lib/Release ${LIBLAS_DIR}/lib64/Release ${LIBLAS_DIR}/lib ${LIBLAS_DIR}/lib64 $ENV{LIBLAS_DIR}/lib/Release $ENV{LIBLAS_DIR}/lib64/Release $ENV{LIBLAS_DIR}/lib $ENV{LIBLAS_DIR}/lib64 $ENV{LIBLAS_DIR} $ENV{LIBLASDIR}/lib $ENV{LIBLASDIR}/lib64 $ENV{LIBLASDIR} $ENV{LIBLAS_ROOT}/lib $ENV{LIBLAS_ROOT}/lib64 NO_DEFAULT_PATH ) find_library( ${MYLIBRARY} NAMES "${MYLIBRARYNAME}${CMAKE_RELEASE_POSTFIX}" PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;LIBLAS_ROOT]/lib /usr/freeware/lib64 ) if( NOT ${MYLIBRARY}_DEBUG ) if( MYLIBRARY ) set( ${MYLIBRARY}_DEBUG ${MYLIBRARY} ) endif(MYLIBRARY) endif( NOT ${MYLIBRARY}_DEBUG ) endmacro(FIND_LIBLAS_LIBRARY LIBRARY LIBRARYNAME) FIND_LIBLAS_LIBRARY(LIBLAS_LIBRARY las) FIND_LIBLAS_LIBRARY(LIBLASC_LIBRARY las_c) set(LIBLAS_FOUND "NO") if(LIBLAS_LIBRARY AND LIBLASC_LIBRARY AND LIBLAS_INCLUDE_DIR) FIND_PACKAGE(Boost) # used by LIBLAS if(Boost_FOUND) set(LIBLAS_LIBRARIES ${LIBLAS_LIBRARY} ${LIBLASC_LIBRARY} ) set(LIBLAS_FOUND "YES") endif() endif() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindOSG.cmake0000644000175000017500000000731713151044751023636 0ustar albertoalberto# Locate gdal # This module defines # OSG_LIBRARY # OSG_FOUND, if false, do not try to link to gdal # OSG_INCLUDE_DIR, where to find the headers # # $OSG_DIR is an environment variable that would # correspond to the ./configure --prefix=$OSG_DIR # # Created by Robert Osfield. FIND_PATH(OSG_INCLUDE_DIR osg/Node ${OSG_DIR}/include $ENV{OSG_DIR}/include $ENV{OSG_DIR} $ENV{OSGDIR}/include $ENV{OSGDIR} $ENV{OSG_ROOT}/include NO_DEFAULT_PATH ) FIND_PATH(OSG_INCLUDE_DIR osg/Node) MACRO(FIND_OSG_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_LIBRARY("${MYLIBRARY}_DEBUG" NAMES "${MYLIBRARYNAME}${CMAKE_DEBUG_POSTFIX}" PATHS ${OSG_DIR}/lib/Debug ${OSG_DIR}/lib64/Debug ${OSG_DIR}/lib ${OSG_DIR}/lib64 $ENV{OSG_DIR}/lib/debug $ENV{OSG_DIR}/lib64/debug $ENV{OSG_DIR}/lib $ENV{OSG_DIR}/lib64 $ENV{OSG_DIR} $ENV{OSGDIR}/lib $ENV{OSGDIR}/lib64 $ENV{OSGDIR} $ENV{OSG_ROOT}/lib $ENV{OSG_ROOT}/lib64 NO_DEFAULT_PATH ) FIND_LIBRARY("${MYLIBRARY}_DEBUG" NAMES "${MYLIBRARYNAME}${CMAKE_DEBUG_POSTFIX}" PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/lib /usr/freeware/lib64 ) FIND_LIBRARY(${MYLIBRARY} NAMES "${MYLIBRARYNAME}${CMAKE_RELEASE_POSTFIX}" PATHS ${OSG_DIR}/lib/Release ${OSG_DIR}/lib64/Release ${OSG_DIR}/lib ${OSG_DIR}/lib64 $ENV{OSG_DIR}/lib/Release $ENV{OSG_DIR}/lib64/Release $ENV{OSG_DIR}/lib $ENV{OSG_DIR}/lib64 $ENV{OSG_DIR} $ENV{OSGDIR}/lib $ENV{OSGDIR}/lib64 $ENV{OSGDIR} $ENV{OSG_ROOT}/lib $ENV{OSG_ROOT}/lib64 NO_DEFAULT_PATH ) FIND_LIBRARY(${MYLIBRARY} NAMES "${MYLIBRARYNAME}${CMAKE_RELEASE_POSTFIX}" PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/lib /usr/freeware/lib64 ) IF( NOT ${MYLIBRARY}_DEBUG) IF(MYLIBRARY) SET(${MYLIBRARY}_DEBUG ${MYLIBRARY}) ENDIF(MYLIBRARY) ELSE() IF( NOT MYLIBRARY ) SET(${MYLIBRARY} ${${MYLIBRARY}_DEBUG} ) ENDIF(NOT MYLIBRARY) ENDIF( NOT ${MYLIBRARY}_DEBUG ) ENDMACRO(FIND_OSG_LIBRARY LIBRARY LIBRARYNAME) FIND_OSG_LIBRARY(OSG_LIBRARY osg) FIND_OSG_LIBRARY(OSGGA_LIBRARY osgGA) FIND_OSG_LIBRARY(OSGUTIL_LIBRARY osgUtil) FIND_OSG_LIBRARY(OSGDB_LIBRARY osgDB) FIND_OSG_LIBRARY(OSGTEXT_LIBRARY osgText) FIND_OSG_LIBRARY(OSGWIDGET_LIBRARY osgWidget) FIND_OSG_LIBRARY(OSGQT_LIBRARY osgQt) FIND_OSG_LIBRARY(OSGTERRAIN_LIBRARY osgTerrain) FIND_OSG_LIBRARY(OSGFX_LIBRARY osgFX) FIND_OSG_LIBRARY(OSGVIEWER_LIBRARY osgViewer) FIND_OSG_LIBRARY(OSGVOLUME_LIBRARY osgVolume) FIND_OSG_LIBRARY(OSGMANIPULATOR_LIBRARY osgManipulator) FIND_OSG_LIBRARY(OSGANIMATION_LIBRARY osgAnimation) FIND_OSG_LIBRARY(OSGPARTICLE_LIBRARY osgParticle) FIND_OSG_LIBRARY(OSGSHADOW_LIBRARY osgShadow) FIND_OSG_LIBRARY(OSGPRESENTATION_LIBRARY osgPresentation) FIND_OSG_LIBRARY(OSGSIM_LIBRARY osgSim) FIND_OSG_LIBRARY(OPENTHREADS_LIBRARY OpenThreads) SET(OSG_FOUND "NO") IF(OSG_LIBRARY AND OSG_INCLUDE_DIR) SET(OSG_FOUND "YES") ENDIF(OSG_LIBRARY AND OSG_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindRSVG.cmake0000644000175000017500000000055513151044751023764 0ustar albertoalberto#use pkg-config to find various modues INCLUDE(FindPkgConfig OPTIONAL) IF(PKG_CONFIG_FOUND) INCLUDE(FindPkgConfig) #Version 2.35 introduces the rsvg_cleanup function which is used PKG_CHECK_MODULES(RSVG librsvg-2.0>=2.35) PKG_CHECK_MODULES(CAIRO cairo) IF (RSVG_FOUND AND NOT CAIRO_FOUND) SET(RSVG_FOUND FALSE) ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindQuartzCore.cmake0000644000175000017500000000111213151044751025270 0ustar albertoalberto# Locate Apple QuartzCore # This module defines # QUARTZCORE_LIBRARY # QUARTZCORE_FOUND, if false, do not try to link to QUARTZCORE # QUARTZCORE_INCLUDE_DIR, where to find the headers # # $QUARTZCORE_DIR is an environment variable that would # correspond to the ./configure --prefix=$QUARTZCORE_DIR # # Created by Stephan Maximilian Huber. IF(APPLE) FIND_PATH(QUARTZCORE_INCLUDE_DIR QuartzCore/QuartzCore.h) FIND_LIBRARY(QUARTZCORE_LIBRARY QuartzCore) ENDIF() SET(QUARTZCORE_FOUND "NO") IF(QUARTZCORE_LIBRARY AND QUARTZCORE_INCLUDE_DIR) SET(QUARTZCORE_FOUND "YES") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindFOX.cmake0000644000175000017500000000277013151044751023640 0ustar albertoalberto# Locate gdal # This module defines # FOX_LIBRARY # FOX_FOUND, if false, do not try to link to gdal # FOX_INCLUDE_DIR, where to find the headers # # $FOX_DIR is an environment variable that would # correspond to the ./configure --prefix=$FOX_DIR # # Created by Robert Osfield. FIND_PATH(FOX_INCLUDE_DIR fx.h $ENV{FOX_DIR}/include/fox-1.6 $ENV{FOX_DIR}/fox-1.6 ~/Library/Frameworks/fox-1.6 /Library/Frameworks/fox-1.6 /usr/local/include/fox-1.6 /usr/include/fox-1.6 /sw/include/fox-1.6 # Fink /opt/local/include/fox-1.6 # DarwinPorts /opt/csw/include/fox-1.6 # Blastwave /opt/include/fox-1.6 /usr/freeware/include/fox-1.6 $ENV{FOX_DIR}/include $ENV{FOX_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include ) MACRO(FIND_FOX_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_LIBRARY(${MYLIBRARY} NAMES ${MYLIBRARYNAME} PATHS $ENV{FOX_DIR}/lib $ENV{FOX_DIR} ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) ENDMACRO(FIND_FOX_LIBRARY LIBRARY LIBRARYNAME) FIND_FOX_LIBRARY(FOX_LIBRARY FOX-1.6) SET(FOX_FOUND "NO") IF(FOX_LIBRARY AND FOX_INCLUDE_DIR) SET(FOX_FOUND "YES") ENDIF(FOX_LIBRARY AND FOX_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/UtilityMacros.cmake0000644000175000017500000001613513151044751025213 0ustar albertoalberto INCLUDE(ListHandle) #--------------------------------------------------- # Macro: FILTER_OUT FILTERS INPUTS OUTPUT # # Mimicks Gnu Make's $(filter-out) which removes elements # from a list that match the pattern. # Arguments: # FILTERS - list of patterns that need to be removed # INPUTS - list of inputs that will be worked on # OUTPUT - the filtered list to be returned # # Example: # SET(MYLIST this that and the other) # SET(FILTS this that) # # FILTER_OUT("${FILTS}" "${MYLIST}" OUT) # MESSAGE("OUTPUT = ${OUT}") # # The output - # OUTPUT = and;the;other # #--------------------------------------------------- MACRO(FILTER_OUT FILTERS INPUTS OUTPUT) SET(FOUT "") FOREACH(INP ${INPUTS}) SET(FILTERED 0) FOREACH(FILT ${FILTERS}) IF(${FILTERED} EQUAL 0) IF("${FILT}" STREQUAL "${INP}") SET(FILTERED 1) ENDIF() ENDIF() ENDFOREACH() IF(${FILTERED} EQUAL 0) SET(FOUT ${FOUT} ${INP}) ENDIF() ENDFOREACH(INP ${INPUTS}) SET(${OUTPUT} ${FOUT}) ENDMACRO() #--------------------------------------------------- # Macro: GET_HEADERS_EXTENSIONLESS DIR GLOB_PATTERN OUTPUT # #--------------------------------------------------- MACRO(GET_HEADERS_EXTENSIONLESS DIR GLOB_PATTERN OUTPUT) FILE(GLOB TMP "${DIR}/${GLOB_PATTERN}" ) #FOREACH(F ${TMP}) # MESSAGE(STATUS "header-->${F}<--") #ENDFOREACH(F ${TMP}) FILTER_OUT("${DIR}/CVS" "${TMP}" TMP) FILTER_OUT("${DIR}/cvs" "${TMP}" ${OUTPUT}) FILTER_OUT("${DIR}/.svn" "${TMP}" ${OUTPUT}) ENDMACRO() #--------------------------------------------------- # Macro: ADD_DIRS_TO_ENV_VAR _VARNAME # #--------------------------------------------------- MACRO(ADD_DIRS_TO_ENV_VAR _VARNAME ) FOREACH(_ADD_PATH ${ARGN}) FILE(TO_NATIVE_PATH ${_ADD_PATH} _ADD_NATIVE) #SET(_CURR_ENV_PATH $ENV{PATH}) #LIST(SET _CURR_ENV_PATH ${_ADD_PATH}) #SET(ENV{PATH} ${_CURR_ENV_PATH})${_FILE} IF(WIN32) SET(ENV{${_VARNAME}} "$ENV{${_VARNAME}};${_ADD_NATIVE}") ELSE() SET(ENV{${_VARNAME}} "$ENV{${_VARNAME}}:${_ADD_NATIVE}") ENDIF() #MESSAGE(" env ${_VARNAME} --->$ENV{${_VARNAME}}<---") ENDFOREACH() ENDMACRO() #--------------------------------------------------- # Macro: CORRECT_PATH VAR PATH # # Corrects slashes in PATH to be cmake conformous ( / ) # and puts result in VAR #--------------------------------------------------- MACRO(CORRECT_PATH VAR PATH) SET(${VAR} ${PATH}) IF(WIN32) STRING(REGEX REPLACE "/" "\\\\" ${VAR} "${PATH}") ENDIF() ENDMACRO() #--------------------------------------------------- # Macro: TARGET_LOCATIONS_SET_FILE FILE # TODO: Ok, this seems a bit ridiculuous. #--------------------------------------------------- MACRO(TARGET_LOCATIONS_SET_FILE FILE) SET(ACCUM_FILE_TARGETS ${FILE}) FILE(WRITE ${ACCUM_FILE_TARGETS} "") ENDMACRO() #--------------------------------------------------- # Macro: TARGET_LOCATIONS_ACCUM TARGET_NAME # #--------------------------------------------------- MACRO(TARGET_LOCATIONS_ACCUM TARGET_NAME) IF(ACCUM_FILE_TARGETS) IF(EXISTS ${ACCUM_FILE_TARGETS}) GET_TARGET_PROPERTY(_FILE_LOCATION ${TARGET_NAME} LOCATION) FILE(APPEND ${ACCUM_FILE_TARGETS} "${_FILE_LOCATION};") #SET(_TARGETS_LIST ${_TARGETS_LIST} "${_FILE_LOCATION}" CACHE INTERNAL "lista dll") #MESSAGE("adding target -->${TARGET_NAME}<-- file -->${_FILE_LOCATION}<-- to list -->${_TARGETS_LIST}<--") #SET(ACCUM_FILE_TARGETS ${ACCUM_FILE_TARGETS} ${_FILE_LOCATION}) ENDIF() ENDIF() ENDMACRO() #--------------------------------------------------- # Macro: TARGET_LOCATIONS_GET_LIST _VAR # #--------------------------------------------------- MACRO(TARGET_LOCATIONS_GET_LIST _VAR) IF(ACCUM_FILE_TARGETS) IF(EXISTS ${ACCUM_FILE_TARGETS}) FILE(READ ${ACCUM_FILE_TARGETS} ${_VAR}) ENDIF(EXISTS ${ACCUM_FILE_TARGETS}) ENDIF() ENDMACRO() #--------------------------------------------------- # Macro: FIND_DEPENDENCY DEPNAME INCLUDEFILE LIBRARY SEARCHPATHLIST # #--------------------------------------------------- MACRO(FIND_DEPENDENCY DEPNAME INCLUDEFILE LIBRARY SEARCHPATHLIST) MESSAGE(STATUS "searching ${DEPNAME} -->${INCLUDEFILE}<-->${LIBRARY}<-->${SEARCHPATHLIST}<--") SET(MY_PATH_INCLUDE ) SET(MY_PATH_LIB ) SET(MY_PATH_BIN ) FOREACH( MYPATH ${SEARCHPATHLIST} ) SET(MY_PATH_INCLUDE ${MY_PATH_INCLUDE} ${MYPATH}/include) SET(MY_PATH_LIB ${MY_PATH_LIB} ${MYPATH}/lib) SET(MY_PATH_BIN ${MY_PATH_BIN} ${MYPATH}/bin) ENDFOREACH() SET(MYLIBRARY "${LIBRARY}") SEPARATE_ARGUMENTS(MYLIBRARY) #MESSAGE( " include paths: -->${MY_PATH_INCLUDE}<--") #MESSAGE( " ${DEPNAME}_INCLUDE_DIR --> ${${DEPNAME}_INCLUDE_DIR}<--") FIND_PATH("${DEPNAME}_INCLUDE_DIR" ${INCLUDEFILE} ${MY_PATH_INCLUDE} ) MARK_AS_ADVANCED("${DEPNAME}_INCLUDE_DIR") #MESSAGE( " ${DEPNAME}_INCLUDE_DIR --> ${${DEPNAME}_INCLUDE_DIR}<--") FIND_LIBRARY("${DEPNAME}_LIBRARY" NAMES ${MYLIBRARY} PATHS ${MY_PATH_LIB} ) IF(${DEPNAME}_LIBRARY) GET_FILENAME_COMPONENT(MYLIBNAME ${${DEPNAME}_LIBRARY} NAME_WE) GET_FILENAME_COMPONENT(MYBINPATH ${${DEPNAME}_LIBRARY} PATH) GET_FILENAME_COMPONENT(MYBINPATH ${MYBINPATH} PATH) SET(MYBINPATH "${MYBINPATH}/bin") IF(EXISTS ${MYBINPATH}) SET(MYFOUND 0) FOREACH(MYPATH ${MY_ACCUM_BINARY_DEP}) IF(MYPATH MATCHES ${MYBINPATH}) SET(MYFOUND 1) #MESSAGE("found -->${MYPATH}<-->${MYBINPATH}<--") ENDIF() ENDFOREACH() IF(MYFOUND EQUAL 0) SET(MY_ACCUM_BINARY_DEP ${MY_ACCUM_BINARY_DEP} ${MYBINPATH}) ENDIF() ENDIF() #MESSAGE("${DEPNAME}_BINDEP searching -->${MYLIBNAME}${CMAKE_SHARED_MODULE_SUFFIX}<--in-->${MY_PATH_BIN}<--") # FIND_FILE("${DEPNAME}_BINDEP" # ${MYLIBNAME}${CMAKE_SHARED_MODULE_SUFFIX} # PATHS ${MY_PATH_BIN} # ) # FIND_LIBRARY("${DEPNAME}_BINDEP" # NAMES ${MYLIBRARY} # PATHS ${MY_PATH_BIN} # ) ENDIF() MARK_AS_ADVANCED("${DEPNAME}_LIBRARY") #MESSAGE( " ${DEPNAME}_LIBRARY --> ${${DEPNAME}_LIBRARY}<--") IF(${DEPNAME}_INCLUDE_DIR) IF(${DEPNAME}_LIBRARY) SET( ${DEPNAME}_FOUND "YES" ) SET( ${DEPNAME}_LIBRARIES ${${DEPNAME}_LIBRARY} ) ENDIF() ENDIF() ENDMACRO() #--------------------------------------------------- # Macro: MACRO_MESSAGE MYTEXT # #--------------------------------------------------- #SET(MACRO_MESSAGE_DEBUG TRUE) MACRO(MACRO_MESSAGE MYTEXT) IF(MACRO_MESSAGE_DEBUG) MESSAGE("in file -->${CMAKE_CURRENT_LIST_FILE}<-- line -->${CMAKE_CURRENT_LIST_LINE}<-- message ${MYTEXT}") ELSE() MESSAGE(STATUS "in file -->${CMAKE_CURRENT_LIST_FILE}<-- line -->${CMAKE_CURRENT_LIST_LINE}<-- message ${MYTEXT}") ENDIF() ENDMACRO() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGLIB.cmake0000644000175000017500000001346513151044751023724 0ustar albertoalberto# - Try to find Glib and its components (gio, gobject etc) # Once done, this will define # # GLIB_FOUND - system has Glib # GLIB_INCLUDE_DIRS - the Glib include directories # GLIB_LIBRARIES - link these to use Glib # # Optionally, the COMPONENTS keyword can be passed to find_package() # and Glib components can be looked for. Currently, the following # components can be used, and they define the following variables if # found: # # gio: GLIB_GIO_LIBRARIES # gobject: GLIB_GOBJECT_LIBRARIES # gmodule: GLIB_GMODULE_LIBRARIES # gthread: GLIB_GTHREAD_LIBRARIES # # Note that the respective _INCLUDE_DIR variables are not set, since # all headers are in the same directory as GLIB_INCLUDE_DIRS. # # Copyright (C) 2012 Raphael Kubo da Costa # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS # IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. if (WIN32) find_library(GLIB_LIBRARIES NAMES glib-2.0 PATHS C:/gstreamer/1.0/x86_64/lib ) else () find_package(PkgConfig) pkg_check_modules(PC_GLIB QUIET glib-2.0) find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS} ) endif () # Files in glib's main include path may include glibconfig.h, which, # for some odd reason, is normally in $LIBDIR/glib-2.0/include. get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH) find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR} PATH_SUFFIXES glib-2.0/include ) if (WIN32) find_path(GLIB_INCLUDE_DIR NAMES glib.h PATHS C:/gstreamer/1.0/x86_64/include PATH_SUFFIXES glib-2.0 ) else() find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0 ) endif() if (GLIBCONFIG_INCLUDE_DIR) set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR}) # Version detection file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS) string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}") set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}") # Additional Glib components. We only look for libraries, as not all of them # have corresponding headers and all headers are installed alongside the main # glib ones. foreach (_component ${GLIB_FIND_COMPONENTS}) if (${_component} STREQUAL "gio") find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES) elseif (${_component} STREQUAL "gobject") find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES) elseif (${_component} STREQUAL "gmodule") find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES) elseif (${_component} STREQUAL "gthread") find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES) elseif (${_component} STREQUAL "gio-unix") # gio-unix is compiled as part of the gio library, but the include paths # are separate from the shared glib ones. Since this is currently only used # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config. pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0) endif () endforeach () include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS} VERSION_VAR GLIB_VERSION) mark_as_advanced( GLIBCONFIG_INCLUDE_DIR GLIB_GIO_LIBRARIES GLIB_GIO_UNIX_LIBRARIES GLIB_GMODULE_LIBRARIES GLIB_GOBJECT_LIBRARIES GLIB_GTHREAD_LIBRARIES GLIB_INCLUDE_DIR GLIB_INCLUDE_DIRS GLIB_LIBRARIES ) else() endif () OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGLCORE.cmake0000644000175000017500000000215213151044751024151 0ustar albertoalberto# Finds the OpenGL Core Profile (cp) header file. # Looks for glcorearb.h # # This script defines the following: # GLCORE_FOUND // Set to TRUE if glcorearb.h is found # GLCORE_INCLUDE_DIR // Parent directory of directory (gl, GL3, or OpenGL) containing the CP header. # GLCORE_GLCOREARB_HEADER // advanced # # GLCORE_ROOT can be set as an environment variable or a CMake variable, # to the parent directory of the gl, GL3, or OpenGL directory containing the CP header. # FIND_PATH( GLCORE_GLCOREARB_HEADER NAMES GL/glcorearb.h GL3/glcorearb.h OpenGL/glcorearb.h gl/glcorearb.h HINTS ${GLCORE_ROOT} PATHS ENV GLCORE_ROOT ) set( GLCORE_INCLUDE_DIR ) if( GLCORE_GLCOREARB_HEADER ) set( GLCORE_INCLUDE_DIR ${GLCORE_GLCOREARB_HEADER} ) endif() # handle the QUIETLY and REQUIRED arguments and set # GLCORE_FOUND to TRUE as appropriate INCLUDE( FindPackageHandleStandardArgs ) FIND_PACKAGE_HANDLE_STANDARD_ARGS( GLCORE "Set GLCORE_ROOT as the parent of the directory containing the OpenGL core profile header." GLCORE_INCLUDE_DIR ) MARK_AS_ADVANCED( GLCORE_INCLUDE_DIR GLCORE_GLCOREARB_HEADER ) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindZeroConf.cmake0000644000175000017500000000230313151044751024721 0ustar albertoalberto# Locate ZeroConf / Bonjour # This module defines # ZEROCONF_LIBRARY # ZEROCONF_FOUND, if false, do not try to link to gdal # ZEROCONF_INCLUDE_DIR, where to find the headers # # $ZEROCONF_DIR is an environment variable that would # correspond to the ./configure --prefix=$ZEROCONF_DIR # Created by Stephan Maximilian Huber SET(ZEROCONF_FOUND "NO") IF(APPLE) # bonjour is part of the system on os x / ios SET(ZEROCONF_FOUND "YES") ELSE() IF(WIN32) # find the Bonjour SDK FIND_PATH(ZEROCONF_INCLUDE_DIR dnssd.h $ENV{ZEROCONF_DIR}/include $ENV{ZEROCONF_DIR} NO_DEFAULT_PATH ) FIND_PATH(ZEROCONF_INCLUDE_DIR dnssd.h PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(ZEROCONF_INCLUDE_DIR dnssd.h) FIND_LIBRARY(ZEROCONF_LIBRARY dnssd PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(ZEROCONF_LIBRARY dnssd) SET(ZEROCONF_FOUND "NO") IF(ZEROCONF_LIBRARY AND ZEROCONF_INCLUDE_DIR) SET(ZEROCONF_FOUND "YES") ENDIF() ELSE() # TODO find AVAHI on linux ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindInventor.cmake0000644000175000017500000001304713151044751025007 0ustar albertoalberto# # Find Open Inventor # # This module defines: # INVENTOR_FOUND, if false, do not try to link against Inventor. # INVENTOR_INCLUDE_DIR, where to find headers. # INVENTOR_LIBRARY, the library to link against. # INVENTOR_LIBRARY_DEBUG, the debug library to link against. # INVENTOR_SOWIN_LIBRARY, the SoWin library - window binding library for Inventor # INVENTOR_SOWIN_LIBRARY, the SoWin debug library # INVENTOR_SOXT_LIBRARY, the SoXt library - window binding library for Inventor # INVENTOR_SOXT_LIBRARY, the SoXt debug library # # # Inventor # # notes: # - Coin is honored over SGI Inventor # - Coin is detected by coin-config script, COINDIR environment variable, # and finally standard system locations are searched # - SGI Inventor is searched at standard system locations only # # coin-config tells much of Coin instalation (if present) execute_process (COMMAND coin-config --prefix OUTPUT_VARIABLE COIN_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) # try to find Inventor includes (priority paths) FIND_PATH(INVENTOR_INCLUDE_DIR Inventor/So.h ${COIN_PREFIX}/include $ENV{COINDIR}/include NO_DEFAULT_PATH ) # try to find Inventor includes (regular paths) FIND_PATH(INVENTOR_INCLUDE_DIR Inventor/So.h /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) # default Inventor lib search paths SET(INVENTOR_LIB_SEARCH_PATH /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib ) # try to find Coin release lib (priority paths) FIND_LIBRARY(INVENTOR_LIBRARY_RELEASE NAMES coin5 coin4 coin3 coin2 coin1 Coin PATHS ${COIN_PREFIX}/lib $ENV{COINDIR}/lib NO_DEFAULT_PATH ) # try to find Coin release lib (regular paths) FIND_LIBRARY(INVENTOR_LIBRARY_RELEASE NAMES coin5 coin4 coin3 coin2 coin1 Coin PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # try to find SGI Inventor lib FIND_LIBRARY(INVENTOR_LIBRARY_RELEASE NAMES Inventor PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # try to find Coin debug lib (priority paths) FIND_LIBRARY(INVENTOR_LIBRARY_DEBUG NAMES coin5d coin4d coin3d coin2d coin1d PATHS ${COIN_PREFIX}/lib $ENV{COINDIR}/lib NO_DEFAULT_PATH ) # try to find Coin debug lib (regular paths) FIND_LIBRARY(INVENTOR_LIBRARY_DEBUG NAMES coin5d coin4d coin3d coin2d coin1d PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # set release to debug if only debug found IF(NOT INVENTOR_LIBRARY_RELEASE AND INVENTOR_LIBRARY_DEBUG) SET(INVENTOR_LIBRARY_RELEASE ${INVENTOR_LIBRARY_DEBUG}) ENDIF(NOT INVENTOR_LIBRARY_RELEASE AND INVENTOR_LIBRARY_DEBUG) # set debug to release (if only release found) IF(NOT INVENTOR_LIBRARY_DEBUG AND INVENTOR_LIBRARY_RELEASE) SET(INVENTOR_LIBRARY_DEBUG ${INVENTOR_LIBRARY_RELEASE}) ENDIF(NOT INVENTOR_LIBRARY_DEBUG AND INVENTOR_LIBRARY_RELEASE) # INVENTOR_LIBRARY IF (CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) SET(INVENTOR_LIBRARY optimized ${INVENTOR_LIBRARY_RELEASE} debug ${INVENTOR_LIBRARY_DEBUG}) ELSE(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) SET(INVENTOR_LIBRARY ${INVENTOR_LIBRARY_RELEASE}) ENDIF(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) # set INVENTOR_FOUND appropriately SET(INVENTOR_FOUND "NO") IF(INVENTOR_INCLUDE_DIR AND INVENTOR_LIBRARY) SET(INVENTOR_FOUND "YES") ENDIF(INVENTOR_INCLUDE_DIR AND INVENTOR_LIBRARY) # # SoWin # # notes: SoWin is searched by COINDIR environment variable # (as expected to be located at Windows platform) # try to find SoWin lib (priority paths) FIND_LIBRARY(INVENTOR_SOWIN_LIBRARY NAMES sowin1 PATHS $ENV{COINDIR}/lib NO_DEFAULT_PATH ) # try to find SoWin lib (regular paths) FIND_LIBRARY(INVENTOR_SOWIN_LIBRARY NAMES sowin1 PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # try to find SoWin debug lib (priority paths) FIND_LIBRARY(INVENTOR_SOWIN_LIBRARY_DEBUG NAMES sowin1d PATHS $ENV{COINDIR}/lib NO_DEFAULT_PATH ) # try to find SoWin debug lib (regular paths) FIND_LIBRARY(INVENTOR_SOWIN_LIBRARY_DEBUG NAMES sowin1d PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # SoWin debug library defaults to non-debug lib IF(NOT INVENTOR_SOWIN_LIBRARY_DEBUG) IF(INVENTOR_SOWIN_LIBRARY) SET(INVENTOR_SOWIN_LIBRARY_DEBUG INVENTOR_SOWIN_LIBRARY) ENDIF(INVENTOR_SOWIN_LIBRARY) ENDIF(NOT INVENTOR_SOWIN_LIBRARY_DEBUG) # # SoXt # # notes: # - SoXt is detected by soxt-config script (as expected by # Coin's SoXt on Linux/Unix) and on standard system locations # - SGI's InventorXt support is missing now # # soxt-config tells much of SoXt instalation (if present) execute_process (COMMAND soxt-config --prefix OUTPUT_VARIABLE SOXT_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) # try to find SoXt lib (priority paths) FIND_LIBRARY(INVENTOR_SOXT_LIBRARY NAMES soxt1 SoXt PATHS ${SOXT_PREFIX}/lib $ENV{COINDIR}/lib NO_DEFAULT_PATH ) # try to find SoXt lib (regular paths) FIND_LIBRARY(INVENTOR_SOXT_LIBRARY NAMES soxt1 SoXt PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # try to find SoXt debug lib (priority paths) FIND_LIBRARY(INVENTOR_SOXT_LIBRARY_DEBUG NAMES soxt1d PATHS ${SOXT_PREFIX}/lib $ENV{COINDIR}/lib NO_DEFAULT_PATH ) # try to find SoXt debug lib (regular paths) FIND_LIBRARY(INVENTOR_SOXT_LIBRARY_DEBUG NAMES soxt1d PATHS ${INVENTOR_LIB_SEARCH_PATH} ) # SoXt debug library defaults to non-debug lib IF(NOT INVENTOR_SOXT_LIBRARY_DEBUG) IF(INVENTOR_SOXT_LIBRARY) SET(INVENTOR_SOXT_LIBRARY_DEBUG INVENTOR_SOXT_LIBRARY) ENDIF(INVENTOR_SOXT_LIBRARY) ENDIF(NOT INVENTOR_SOXT_LIBRARY_DEBUG) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindDirectShow.cmake0000644000175000017500000000405713151044751025257 0ustar albertoalberto# Locate directshow # This module defines # DIRECTSHOW_LIBRARIES # DIRECTSHOW_FOUND, if false, do not try to link to directshow # DIRECTSHOW_INCLUDE_DIR, where to find the headers # # $DIRECTSHOW_DIR is an environment variable that would # point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) # # Created by Cedric Pinson. # SET(DIRECTSHOW_FOUND "NO") SET(DIRECTSHOW_SAMPLE_ROOT "$ENV{DIRECTSHOW_DIR}" CACHE PATH "Location of DirectShow sample in devkit") IF(WIN32) FIND_PATH(DIRECTSHOW_STRMBASE_INCLUDE_DIRS renbase.h PATHS ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/ $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/ DOC "Location of DirectShow Base include on the windows devkit" ) FIND_LIBRARY(DIRECTSHOW_STRMBASE_LIBRARY_RELEASE strmbase PATHS ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release_MBCS/ # sdk 6.1 $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release_MBCS/ # sdk 6.1 ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release/ # sdk 2003 $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release/ # sdk 2003 DOC "Location of DirectShow Base library on the windows devkit" ) FIND_LIBRARY(DIRECTSHOW_STRMBASE_LIBRARY_DEBUG strmbasd PATHS ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug_MBCS/ # sdk 6.1 $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug_MBCS/ # sdk 6.1 ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug/ # sdk 2003 $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug/ # sdk 2003 DOC "Location of DirectShow Base library on the windows devkit" ) IF (DIRECTSHOW_STRMBASE_INCLUDE_DIRS AND DIRECTSHOW_STRMBASE_LIBRARY_RELEASE) SET(WIN_LIBS winmm d3d9 d3dx9 kernel32 user32 gdi32 winspool shell32 ole32 oleaut32 uuid comdlg32 advapi32) SET(DIRECTSHOW_FOUND "YES") SET(DIRECTSHOW_LIBRARY_DEBUG ${DIRECTSHOW_STRMBASE_LIBRARY_DEBUG} ) SET(DIRECTSHOW_LIBRARY ${DIRECTSHOW_STRMBASE_LIBRARY_RELEASE} ) SET(DIRECTSHOW_INLUDE_DIRS ${DIRECTSHOW_STRMBASE_INCLUDE_DIRS} ) ENDIF() ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindGDAL.cmake0000644000175000017500000000512513151044751023710 0ustar albertoalberto# Locate gdal # This module defines # GDAL_LIBRARY # GDAL_FOUND, if false, do not try to link to gdal # GDAL_INCLUDE_DIR, where to find the headers # # $GDALDIR is an environment variable that would # correspond to the ./configure --prefix=$GDAL_DIR # used in building gdal. # # Created by Eric Wing. I'm not a gdal user, but OpenSceneGraph uses it # for osgTerrain so I whipped this module together for completeness. # I actually don't know the conventions or where files are typically # placed in distros. # Any real gdal users are encouraged to correct this (but please don't # break the OS X framework stuff when doing so which is what usually seems # to happen). # This makes the presumption that you are include gdal.h like # #include "gdal.h" # prefer FindGDAL from cmake distribution if(EXISTS ${CMAKE_ROOT}/Modules/FindGDAL.cmake) include(${CMAKE_ROOT}/Modules/FindGDAL.cmake) if(GDAL_FOUND) return() endif() endif() FIND_PATH(GDAL_INCLUDE_DIR gdal.h PATHS $ENV{GDAL_DIR} NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(GDAL_INCLUDE_DIR gdal.h PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES include ) FIND_PATH(GDAL_INCLUDE_DIR gdal.h PATHS ~/Library/Frameworks/gdal.framework/Headers /Library/Frameworks/gdal.framework/Headers /usr/local/include/gdal /usr/local/include/GDAL /usr/local/include /usr/include/gdal /usr/include/GDAL /usr/include /sw/include/gdal /sw/include/GDAL /sw/include # Fink /opt/local/include/gdal /opt/local/include/GDAL /opt/local/include # DarwinPorts /opt/csw/include/gdal /opt/csw/include/GDAL /opt/csw/include # Blastwave /opt/include/gdal /opt/include/GDAL /opt/include ) FIND_LIBRARY(GDAL_LIBRARY NAMES gdal gdal_i gdal1.7.0 gdal1.6.0 gdal1.5.0 gdal1.4.0 gdal1.3.2 GDAL PATHS $ENV{GDAL_DIR} NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(GDAL_LIBRARY NAMES gdal gdal_i gdal1.7.0 gdal1.6.0 gdal1.5.0 gdal1.4.0 gdal1.3.2 GDAL PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(GDAL_LIBRARY NAMES gdal gdal_i gdal1.7.0 gdal1.6.0 gdal1.5.0 gdal1.4.0 gdal1.3.2 GDAL PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw /opt/local /opt/csw /opt /usr/freeware [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;GDAL_ROOT]/lib PATH_SUFFIXES lib64 lib ) SET(GDAL_FOUND "NO") IF(GDAL_LIBRARY AND GDAL_INCLUDE_DIR) SET(GDAL_FOUND "YES") ENDIF(GDAL_LIBRARY AND GDAL_INCLUDE_DIR) OpenSceneGraph-OpenSceneGraph-3.4.1/CMakeModules/FindOurDCMTK.cmake0000644000175000017500000001553613151044751024540 0ustar albertoalberto# - find DCMTK libraries # # DCMTK_INCLUDE_DIRS - Directories to include to use DCMTK # DCMTK_LIBRARIES - Files to link against to use DCMTK # DCMTK_FOUND - If false, don't try to use DCMTK # DCMTK_DIR - (optional) Source directory for DCMTK # # DCMTK_DIR can be used to make it simpler to find the various include # directories and compiled libraries if you've just compiled it in the # source tree. Just set it to the root of the tree where you extracted # the source. # # Written for VXL by Amitha Perera. # Modified by Robert Osfied to enable support for install placements of DCMTK 3.5.4 versions onwards FIND_PATH( DCMTK_ROOT_INCLUDE_DIR dcmtk/config/osconfig.h ${DCMTK_DIR}/config/include ${DCMTK_DIR}/include /usr/local/dicom/include /usr/local/include/ /usr/include/ /usr/local/dicom/include/ ) FIND_PATH( DCMTK_config_INCLUDE_DIR osconfig.h ${DCMTK_ROOT_INCLUDE_DIR}/dcmtk/config ${DCMTK_DIR}/config/include ${DCMTK_DIR}/include /usr/local/dicom/include /usr/local/include/dcmtk/config /usr/include/dcmtk/config /usr/local/dicom/include/dcmtk/config ) FIND_PATH( DCMTK_ofstd_INCLUDE_DIR ofstdinc.h ${DCMTK_ROOT_INCLUDE_DIR}/dcmtk/ofstd ${DCMTK_DIR}/ofstd/include ${DCMTK_DIR}/include/ofstd /usr/local/dicom/include/dcmtk/ofstd /usr/local/include/dcmtk/ofstd /usr/include/dcmtk/ofstd /usr/local/dicom/include/dcmtk/ofstd ) FIND_LIBRARY( DCMTK_ofstd_LIBRARY ofstd PATHS ${DCMTK_DIR}/ofstd/libsrc ${DCMTK_DIR}/ofstd/libsrc/Release ${DCMTK_DIR}/ofstd/libsrc/Debug ${DCMTK_DIR}/ofstd/Release ${DCMTK_DIR}/ofstd/Debug ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_PATH( DCMTK_dcmdata_INCLUDE_DIR dctypes.h ${DCMTK_ROOT_INCLUDE_DIR}/dcmtk/dcmdata ${DCMTK_DIR}/dcmdata/include ${DCMTK_DIR}/include/dcmdata /usr/local/dicom/include/dcmtk/dcmdata /usr/local/include/dcmtk/dcmdata /usr/include/dcmtk/dcmdata /usr/local/dicom/include/dcmtk/dcmdata ) FIND_LIBRARY( DCMTK_dcmdata_LIBRARY dcmdata PATHS ${DCMTK_DIR}/dcmdata/libsrc ${DCMTK_DIR}/dcmdata/libsrc/Release ${DCMTK_DIR}/dcmdata/libsrc/Debug ${DCMTK_DIR}/dcmdata/Release ${DCMTK_DIR}/dcmdata/Debug ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_PATH( DCMTK_dcmimgle_INCLUDE_DIR dcmimage.h ${DCMTK_ROOT_INCLUDE_DIR}/dcmtk/dcmimgle ${DCMTK_DIR}/dcmimgle/include ${DCMTK_DIR}/include/dcmimgle /usr/local/dicom/include/dcmtk/dcmimgle /usr/local/include/dcmtk/dcmimgle /usr/include/dcmtk/dcmimgle /usr/local/dicom/include/dcmtk/dcmimgle ) FIND_LIBRARY( DCMTK_dcmimgle_LIBRARY dcmimgle PATHS ${DCMTK_DIR}/dcmimgle/libsrc ${DCMTK_DIR}/dcmimgle/libsrc/Release ${DCMTK_DIR}/dcmimgle/libsrc/Debug ${DCMTK_DIR}/dcmimgle/Release ${DCMTK_DIR}/dcmimgle/Debug ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_PATH( DCMTK_dcmimage_INCLUDE_DIR diregist.h ${DCMTK_ROOT_INCLUDE_DIR}/dcmtk/dcmimage ${DCMTK_DIR}/dcmimage/include ${DCMTK_DIR}/include/dcmimage /usr/local/dicom/include/dcmtk/dcmimage /usr/local/include/dcmtk/dcmimage /usr/include/dcmtk/dcmimage /usr/local/dicom/include/dcmtk/dcmimage ) FIND_LIBRARY( DCMTK_dcmimage_LIBRARY dcmimage PATHS ${DCMTK_DIR}/dcmimage/libsrc ${DCMTK_DIR}/dcmimage/libsrc/Release ${DCMTK_DIR}/dcmimage/libsrc/Debug ${DCMTK_DIR}/dcmimage/Release ${DCMTK_DIR}/dcmimage/Debug ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_LIBRARY(DCMTK_imagedb_LIBRARY imagedb PATHS ${DCMTK_DIR}/imagectn/libsrc/Release ${DCMTK_DIR}/imagectn/libsrc/ ${DCMTK_DIR}/imagectn/libsrc/Debug ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_LIBRARY(DCMTK_dcmnet_LIBRARY dcmnet PATHS ${DCMTK_DIR}/dcmnet/libsrc/Release ${DCMTK_DIR}/dcmnet/libsrc/Debug ${DCMTK_DIR}/dcmnet/libsrc/ ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_LIBRARY(DCMTK_oflog_LIBRARY oflog PATHS ${DCMTK_DIR}/dcmnet/libsrc/Release ${DCMTK_DIR}/dcmnet/libsrc/Debug ${DCMTK_DIR}/dcmnet/libsrc/ ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) FIND_LIBRARY(DCMTK_ofstd_LIBRARY ofstd PATHS ${DCMTK_DIR}/dcmnet/libsrc/Release ${DCMTK_DIR}/dcmnet/libsrc/Debug ${DCMTK_DIR}/dcmnet/libsrc/ ${DCMTK_DIR}/lib /usr/local/dicom/lib /usr/local/lib64 /usr/lib64 /usr/local/lib /usr/lib /usr/local/dicom/lib PATH_SUFFIXES dcmtk ) IF( DCMTK_config_INCLUDE_DIR AND DCMTK_ofstd_INCLUDE_DIR AND DCMTK_ofstd_LIBRARY AND DCMTK_dcmdata_INCLUDE_DIR AND DCMTK_dcmdata_LIBRARY AND DCMTK_dcmimgle_INCLUDE_DIR AND DCMTK_dcmimgle_LIBRARY AND DCMTK_dcmimage_INCLUDE_DIR AND DCMTK_dcmimage_LIBRARY ) SET( DCMTK_FOUND "YES" ) SET( DCMTK_INCLUDE_DIRS ${DCMTK_config_INCLUDE_DIR} ${DCMTK_ofstd_INCLUDE_DIR} ${DCMTK_dcmdata_INCLUDE_DIR} ${DCMTK_dcmimgle_INCLUDE_DIR} ${DCMTK_dcmimage_INCLUDE_DIR} ) SET( DCMTK_LIBRARIES ${DCMTK_dcmimgle_LIBRARY} ${DCMTK_dcmimage_LIBRARY} ${DCMTK_dcmdata_LIBRARY} ${DCMTK_ofstd_LIBRARY} ${DCMTK_config_LIBRARY} ) IF(DCMTK_imagedb_LIBRARY) SET( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_imagedb_LIBRARY} ) ENDIF() IF(DCMTK_dcmnet_LIBRARY) SET( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_dcmnet_LIBRARY} ) ENDIF() IF(DCMTK_oflog_LIBRARY) SET( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_oflog_LIBRARY} ) ENDIF() IF(DCMTK_ofstd_LIBRARY) SET( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_ofstd_LIBRARY} ) ENDIF() IF( WIN32 ) SET( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} netapi32 ) ENDIF() ENDIF() IF( NOT DCMTK_FOUND ) SET( DCMTK_DIR "" CACHE PATH "Root of DCMTK source tree (optional)." ) MARK_AS_ADVANCED( DCMTK_DIR ) ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/src/0000755000175000017500000000000013151044751017651 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/0000755000175000017500000000000013151044751022655 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TabBoxDragger.cpp0000644000175000017500000000525113151044751026037 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include using namespace osgManipulator; TabBoxDragger::TabBoxDragger() { for (int i=0; i<6; ++i) { _planeDraggers.push_back(new TabPlaneDragger()); addChild(_planeDraggers[i].get()); addDragger(_planeDraggers[i].get()); } { _planeDraggers[0]->setMatrix(osg::Matrix::translate(osg::Vec3(0.0,0.5,0.0))); } { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, -1.0f, 0.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); _planeDraggers[1]->setMatrix(osg::Matrix(rotation)*osg::Matrix::translate(osg::Vec3(0.0,-0.5,0.0))); } { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); _planeDraggers[2]->setMatrix(osg::Matrix(rotation)*osg::Matrix::translate(osg::Vec3(0.0,0.0,-0.5))); } { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 1.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 1.0f)); _planeDraggers[3]->setMatrix(osg::Matrix(rotation)*osg::Matrix::translate(osg::Vec3(0.0,0.0,0.5))); } { osg::Quat rotation; rotation.makeRotate(osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); _planeDraggers[4]->setMatrix(osg::Matrix(rotation)*osg::Matrix::translate(osg::Vec3(-0.5,0.0,0.0))); } { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 1.0f, 0.0f), osg::Vec3(1.0f, 0.0f, 0.0f)); _planeDraggers[5]->setMatrix(osg::Matrix(rotation)*osg::Matrix::translate(osg::Vec3(0.5,0.0,0.0))); } setParentDragger(getParentDragger()); } TabBoxDragger::~TabBoxDragger() { } void TabBoxDragger::setupDefaultGeometry() { for (unsigned int i=0; i<_planeDraggers.size(); ++i) _planeDraggers[i]->setupDefaultGeometry(false); } void TabBoxDragger::setPlaneColor(const osg::Vec4& color) { for (unsigned int i=0; i<_planeDraggers.size(); ++i) _planeDraggers[i]->setPlaneColor(color); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TabPlaneTrackballDragger.cpp0000644000175000017500000000275513151044751030174 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include #include #include using namespace osgManipulator; TabPlaneTrackballDragger::TabPlaneTrackballDragger() { _trackballDragger = new TrackballDragger(true); addChild(_trackballDragger.get()); addDragger(_trackballDragger.get()); _tabPlaneDragger = new TabPlaneDragger(); addChild(_tabPlaneDragger.get()); addDragger(_tabPlaneDragger.get()); setParentDragger(getParentDragger()); } TabPlaneTrackballDragger::~TabPlaneTrackballDragger() { } void TabPlaneTrackballDragger::setupDefaultGeometry() { _trackballDragger->setupDefaultGeometry(); _tabPlaneDragger->setupDefaultGeometry(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Constraint.cpp0000644000175000017500000001642213151044751025512 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include using namespace osgManipulator; namespace { double round_to_nearest_int(double x) { return floor(x+0.5); } osg::Vec3d snap_point_to_grid(const osg::Vec3d& point, const osg::Vec3d& origin, const osg::Vec3d& spacing) { osg::Vec3d scale; scale[0] = spacing[0] ? round_to_nearest_int((point[0] - origin[0]) / spacing[0]) : 1.0; scale[1] = spacing[1] ? round_to_nearest_int((point[1] - origin[1]) / spacing[1]) : 1.0; scale[2] = spacing[2] ? round_to_nearest_int((point[2] - origin[2]) / spacing[2]) : 1.0; osg::Vec3d snappedPoint = origin; snappedPoint += osg::Vec3(scale[0]*spacing[0],scale[1]*spacing[1],scale[2]*spacing[2]); return snappedPoint; } } void Constraint::computeLocalToWorldAndWorldToLocal() const { if (!_refNode) { _localToWorld.makeIdentity(); _worldToLocal.makeIdentity(); return; } osg::NodePath pathToRoot; computeNodePathToRoot(const_cast(getReferenceNode()),pathToRoot); _localToWorld = osg::computeLocalToWorld(pathToRoot); _worldToLocal = osg::computeWorldToLocal(pathToRoot); } GridConstraint::GridConstraint(osg::Node& refNode, const osg::Vec3d& origin, const osg::Vec3d& spacing) : Constraint(refNode), _origin(origin), _spacing(spacing) { } bool GridConstraint::constrain(TranslateInLineCommand& command) const { if (command.getStage() == osgManipulator::MotionCommand::START) computeLocalToWorldAndWorldToLocal(); else if (command.getStage() == osgManipulator::MotionCommand::FINISH) return true; osg::Vec3d translatedPoint = command.getLineStart() + command.getTranslation(); osg::Vec3d localTranslatedPoint = (osg::Vec3d(translatedPoint) * command.getLocalToWorld() * getWorldToLocal()); osg::Vec3d newLocalTranslatedPoint = snap_point_to_grid(localTranslatedPoint, _origin, _spacing); command.setTranslation(newLocalTranslatedPoint * getLocalToWorld() * command.getWorldToLocal() - command.getLineStart()); return true; } bool GridConstraint::constrain(TranslateInPlaneCommand& command) const { if (command.getStage() == osgManipulator::MotionCommand::START) computeLocalToWorldAndWorldToLocal(); else if (command.getStage() == osgManipulator::MotionCommand::FINISH) return true; osg::Matrix commandToConstraint = command.getLocalToWorld() * getWorldToLocal(); osg::Matrix constraintToCommand = getLocalToWorld() * command.getWorldToLocal(); // Snap the reference point to grid. osg::Vec3d localRefPoint = command.getReferencePoint() * commandToConstraint; osg::Vec3d snappedLocalRefPoint = snap_point_to_grid(localRefPoint, _origin, _spacing); osg::Vec3d snappedCmdRefPoint = snappedLocalRefPoint * constraintToCommand; // Snap the translated point to grid. osg::Vec3d translatedPoint = snappedCmdRefPoint + command.getTranslation(); osg::Vec3d localTranslatedPoint = osg::Vec3d(translatedPoint) * commandToConstraint; osg::Vec3d newLocalTranslatedPoint = snap_point_to_grid(localTranslatedPoint, _origin, _spacing); // Set the snapped translation. command.setTranslation(newLocalTranslatedPoint * constraintToCommand - snappedCmdRefPoint); return true; } bool GridConstraint::constrain(Scale1DCommand& command) const { if (command.getStage() == osgManipulator::MotionCommand::START) computeLocalToWorldAndWorldToLocal(); else if (command.getStage() == osgManipulator::MotionCommand::FINISH) return true; double scaledPoint = (command.getReferencePoint() - command.getScaleCenter()) * command.getScale() + command.getScaleCenter(); osg::Matrix constraintToCommand = getLocalToWorld() * command.getWorldToLocal(); osg::Vec3d commandOrigin = _origin * constraintToCommand; osg::Vec3d commandSpacing = (_origin + _spacing) * constraintToCommand - commandOrigin; double spacingFactor = commandSpacing[0] ? round_to_nearest_int((scaledPoint-commandOrigin[0])/commandSpacing[0]) : 1.0; double snappedScaledPoint = commandOrigin[0] + commandSpacing[0] * spacingFactor; double denom = (command.getReferencePoint() - command.getScaleCenter()); double snappedScale = (denom) ? (snappedScaledPoint - command.getScaleCenter()) / denom : 1.0; if (snappedScale < command.getMinScale()) snappedScale = command.getMinScale(); command.setScale(snappedScale); return true; } bool GridConstraint::constrain(Scale2DCommand& command) const { if (command.getStage() == osgManipulator::MotionCommand::START) computeLocalToWorldAndWorldToLocal(); else if (command.getStage() == osgManipulator::MotionCommand::FINISH) return true; osg::Vec2d scaledPoint = command.getReferencePoint() - command.getScaleCenter(); scaledPoint[0] *= command.getScale()[0]; scaledPoint[1] *= command.getScale()[1]; scaledPoint += command.getScaleCenter(); osg::Matrix constraintToCommand = getLocalToWorld() * command.getWorldToLocal(); osg::Vec3d commandOrigin = _origin * constraintToCommand; osg::Vec3d commandSpacing = (_origin + _spacing) * constraintToCommand - commandOrigin; osg::Vec2d spacingFactor; spacingFactor[0] = commandSpacing[0] ? round_to_nearest_int((scaledPoint[0] - commandOrigin[0])/commandSpacing[0]) : 1.0; spacingFactor[1] = commandSpacing[2] ? round_to_nearest_int((scaledPoint[1] - commandOrigin[2])/commandSpacing[2]) : 1.0; osg::Vec2d snappedScaledPoint = (osg::Vec2d(commandOrigin[0],commandOrigin[2]) + osg::Vec2d(commandSpacing[0]*spacingFactor[0], commandSpacing[2]*spacingFactor[1])); osg::Vec2d denom = command.getReferencePoint() - command.getScaleCenter(); osg::Vec2d snappedScale; snappedScale[0] = denom[0] ? (snappedScaledPoint[0] - command.getScaleCenter()[0]) / denom[0] : 1.0; snappedScale[1] = denom[1] ? (snappedScaledPoint[1] - command.getScaleCenter()[1]) / denom[1] : 1.0; if (snappedScale[0] < command.getMinScale()[0]) snappedScale[0] = command.getMinScale()[0]; if (snappedScale[1] < command.getMinScale()[1]) snappedScale[1] = command.getMinScale()[1]; command.setScale(snappedScale); return true; } bool GridConstraint::constrain(ScaleUniformCommand&) const { // Can you correctly snap a ScaleUniformCommand using a Grid constraint that has // different spacings in the three axis?? return false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Version.cpp0000644000175000017500000000155213151044751025011 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include extern "C" { const char* osgManipulatorGetVersion() { return osgGetVersion(); } const char* osgManipulatorGetLibraryName() { return "OpenSceneGraph Manipulator Library"; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Translate1DDragger.cpp0000644000175000017500000001602613151044751027004 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include using namespace osgManipulator; Translate1DDragger::Translate1DDragger() : Dragger(), _checkForNodeInNodePath(true) { _projector = new LineProjector; setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } Translate1DDragger::Translate1DDragger(const osg::Vec3d& s, const osg::Vec3d& e) : Dragger(), _checkForNodeInNodePath(true) { _projector = new LineProjector(s,e); setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } Translate1DDragger::~Translate1DDragger() { } bool Translate1DDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (_checkForNodeInNodePath) { if (!pointer.contains(this)) return false; } switch (ea.getEventType()) { // Pick start. case (osgGA::GUIEventAdapter::PUSH): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::NodePath nodePathToRoot; computeNodePathToRoot(*this,nodePathToRoot); osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot); _projector->setLocalToWorld(localToWorld); if (_projector->project(pointer, _startProjectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new TranslateInLineCommand(_projector->getLineStart(), _projector->getLineEnd()); cmd->setStage(MotionCommand::START); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Set color to pick color. setMaterialColor(_pickColor,*this); aa.requestRedraw(); } return true; } // Pick move. case (osgGA::GUIEventAdapter::DRAG): { osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new TranslateInLineCommand(_projector->getLineStart(), _projector->getLineEnd()); cmd->setStage(MotionCommand::MOVE); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); cmd->setTranslation(projectedPoint - _startProjectedPoint); // Dispatch command. dispatch(*cmd); aa.requestRedraw(); } return true; } // Pick finish. case (osgGA::GUIEventAdapter::RELEASE): { osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { osg::ref_ptr cmd = new TranslateInLineCommand(_projector->getLineStart(), _projector->getLineEnd()); cmd->setStage(MotionCommand::FINISH); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Reset color. setMaterialColor(_color,*this); aa.requestRedraw(); } return true; } default: return false; } } void Translate1DDragger::setupDefaultGeometry() { // Get the line length and direction. osg::Vec3 lineDir = _projector->getLineEnd()-_projector->getLineStart(); float lineLength = lineDir.length(); lineDir.normalize(); osg::Geode* geode = new osg::Geode; // Create a left cone. { osg::Cone* cone = new osg::Cone (_projector->getLineStart(), 0.025f * lineLength, 0.10f * lineLength); osg::Quat rotation; rotation.makeRotate(lineDir, osg::Vec3(0.0f, 0.0f, 1.0f)); cone->setRotation(rotation); geode->addDrawable(new osg::ShapeDrawable(cone)); } // Create a right cone. { osg::Cone* cone = new osg::Cone (_projector->getLineEnd(), 0.025f * lineLength, 0.10f * lineLength); osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), lineDir); cone->setRotation(rotation); geode->addDrawable(new osg::ShapeDrawable(cone)); } // Create an invisible cylinder for picking the line. { osg::Cylinder* cylinder = new osg::Cylinder ((_projector->getLineStart()+_projector->getLineEnd())/2, 0.015f * lineLength, lineLength); osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), lineDir); cylinder->setRotation(rotation); osg::Drawable* cylinderGeom = new osg::ShapeDrawable(cylinder); setDrawableToAlwaysCull(*cylinderGeom); geode->addDrawable(cylinderGeom); } osg::Geode* lineGeode = new osg::Geode; // Create a line. { osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(2); (*vertices)[0] = _projector->getLineStart(); (*vertices)[1] = _projector->getLineEnd(); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2)); lineGeode->addDrawable(geometry); } // Turn of lighting for line and set line width. lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::LineWidth* linewidth = new osg::LineWidth(); linewidth->setWidth(2.0f); lineGeode->getOrCreateStateSet()->setAttributeAndModes(linewidth, osg::StateAttribute::ON); // Add line and cones to the scene. addChild(lineGeode); addChild(geode); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TrackballDragger.cpp0000644000175000017500000001434413151044751026562 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include #include #include #include using namespace osgManipulator; namespace { osg::Geometry* createCircleGeometry(float radius, unsigned int numSegments) { const float angleDelta = 2.0f*osg::PI/(float)numSegments; const float r = radius; float angle = 0.0f; osg::Vec3Array* vertexArray = new osg::Vec3Array(numSegments); osg::Vec3Array* normalArray = new osg::Vec3Array(numSegments); for(unsigned int i = 0; i < numSegments; ++i,angle+=angleDelta) { float c = cosf(angle); float s = sinf(angle); (*vertexArray)[i].set(c*r,s*r,0.0f); (*normalArray)[i].set(c,s,0.0f); } osg::Geometry* geometry = new osg::Geometry(); geometry->setVertexArray(vertexArray); geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,vertexArray->size())); return geometry; } } TrackballDragger::TrackballDragger(bool useAutoTransform) { if (useAutoTransform) { float pixelSize = 50.0f; osg::MatrixTransform* scaler = new osg::MatrixTransform; scaler->setMatrix(osg::Matrix::scale(pixelSize, pixelSize, pixelSize)); osg::AutoTransform *at = new osg::AutoTransform; at->setAutoScaleToScreen(true); at->addChild(scaler); AntiSquish* as = new AntiSquish; as->addChild(at); addChild(as); _xDragger = new RotateCylinderDragger(); scaler->addChild(_xDragger.get()); addDragger(_xDragger.get()); _yDragger = new RotateCylinderDragger(); scaler->addChild(_yDragger.get()); addDragger(_yDragger.get()); _zDragger = new RotateCylinderDragger(); scaler->addChild(_zDragger.get()); addDragger(_zDragger.get()); _xyzDragger = new RotateSphereDragger(); scaler->addChild(_xyzDragger.get()); addDragger(_xyzDragger.get()); } else { _xDragger = new RotateCylinderDragger(); addChild(_xDragger.get()); addDragger(_xDragger.get()); _yDragger = new RotateCylinderDragger(); addChild(_yDragger.get()); addDragger(_yDragger.get()); _zDragger = new RotateCylinderDragger(); addChild(_zDragger.get()); addDragger(_zDragger.get()); _xyzDragger = new RotateSphereDragger(); addChild(_xyzDragger.get()); addDragger(_xyzDragger.get()); } _axisLineWidth = 2.0f; _pickCylinderHeight = 0.15f; setParentDragger(getParentDragger()); } TrackballDragger::~TrackballDragger() { } void TrackballDragger::setupDefaultGeometry() { _geode = new osg::Geode; { osg::TessellationHints* hints = new osg::TessellationHints; hints->setCreateTop(false); hints->setCreateBottom(false); hints->setCreateBackFace(false); _cylinder = new osg::Cylinder; _cylinder->setHeight(_pickCylinderHeight); osg::ShapeDrawable* cylinderDrawable = new osg::ShapeDrawable(_cylinder.get(), hints); _geode->addDrawable(cylinderDrawable); setDrawableToAlwaysCull(*cylinderDrawable); _geode->addDrawable(createCircleGeometry(1.0f, 100)); } // Draw in line mode. { osg::PolygonMode* polymode = new osg::PolygonMode; polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE); _geode->getOrCreateStateSet()->setAttributeAndModes(polymode,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); _lineWidth = new osg::LineWidth(_axisLineWidth); _geode->getOrCreateStateSet()->setAttributeAndModes(_lineWidth.get(), osg::StateAttribute::ON); #if !defined(OSG_GLES2_AVAILABLE) _geode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); #endif } // Add line to all the individual 1D draggers. _xDragger->addChild(_geode.get()); _yDragger->addChild(_geode.get()); _zDragger->addChild(_geode.get()); // Rotate X-axis dragger appropriately. { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(1.0f, 0.0f, 0.0f)); _xDragger->setMatrix(osg::Matrix(rotation)); } // Rotate Y-axis dragger appropriately. { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); _yDragger->setMatrix(osg::Matrix(rotation)); } // Send different colors for each dragger. _xDragger->setColor(osg::Vec4(1.0f,0.0f,0.0f,1.0f)); _yDragger->setColor(osg::Vec4(0.0f,1.0f,0.0f,1.0f)); _zDragger->setColor(osg::Vec4(0.0f,0.0f,1.0f,1.0f)); // Add invisible sphere for pick the spherical dragger. { osg::Drawable* sphereDrawable = new osg::ShapeDrawable(new osg::Sphere()); setDrawableToAlwaysCull(*sphereDrawable); osg::Geode* sphereGeode = new osg::Geode; sphereGeode->addDrawable(sphereDrawable); _xyzDragger->addChild(sphereGeode); } } void TrackballDragger::setAxisLineWidth(float linePixelWidth) { _axisLineWidth = linePixelWidth; if (_lineWidth.valid()) _lineWidth->setWidth(linePixelWidth); } void TrackballDragger::setPickCylinderHeight(float pickCylinderHeight) { _pickCylinderHeight = pickCylinderHeight; if (_cylinder.valid()) _cylinder->setHeight(pickCylinderHeight); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Scale1DDragger.cpp0000644000175000017500000001601513151044751026074 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include using namespace osgManipulator; namespace { double computeScale(const osg::Vec3d& startProjectedPoint, const osg::Vec3d& projectedPoint, double scaleCenter) { double denom = startProjectedPoint[0] - scaleCenter; double scale = denom ? (projectedPoint[0] - scaleCenter)/denom : 1.0; return scale; } } Scale1DDragger::Scale1DDragger(ScaleMode scaleMode) : Dragger(), _minScale(0.001), _scaleMode(scaleMode) { _projector = new LineProjector(osg::Vec3d(-0.5,0.0,0.0),osg::Vec3d(0.5,0.0,0.0)); setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } Scale1DDragger::~Scale1DDragger() { } bool Scale1DDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; switch (ea.getEventType()) { // Pick start. case (osgGA::GUIEventAdapter::PUSH): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::NodePath nodePathToRoot; computeNodePathToRoot(*this,nodePathToRoot); osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot); _projector->setLocalToWorld(localToWorld); if (_projector->project(pointer, _startProjectedPoint)) { _scaleCenter = 0.0; if (_scaleMode == SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT) { if ( pointer.contains(_leftHandleNode.get()) ) _scaleCenter = _projector->getLineEnd()[0]; else if ( pointer.contains( _rightHandleNode.get()) ) _scaleCenter = _projector->getLineStart()[0]; } // Generate the motion command. osg::ref_ptr cmd = new Scale1DCommand(); cmd->setStage(MotionCommand::START); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Set color to pick color. setMaterialColor(_pickColor,*this); aa.requestRedraw(); } return true; } // Pick move. case (osgGA::GUIEventAdapter::DRAG): { osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new Scale1DCommand(); // Compute scale. double scale = computeScale(_startProjectedPoint,projectedPoint,_scaleCenter); if (scale < getMinScale()) scale = getMinScale(); // Snap the referencePoint to the line start or line end depending on which is closer. double referencePoint = _startProjectedPoint[0]; if (fabs(_projector->getLineStart()[0] - referencePoint) < fabs(_projector->getLineEnd()[0] - referencePoint)) referencePoint = _projector->getLineStart()[0]; else referencePoint = _projector->getLineEnd()[0]; cmd->setStage(MotionCommand::MOVE); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); cmd->setScale(scale); cmd->setScaleCenter(_scaleCenter); cmd->setReferencePoint(referencePoint); cmd->setMinScale(getMinScale()); // Dispatch command. dispatch(*cmd); aa.requestRedraw(); } return true; } // Pick finish. case (osgGA::GUIEventAdapter::RELEASE): { osg::ref_ptr cmd = new Scale1DCommand(); cmd->setStage(MotionCommand::FINISH); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Reset color. setMaterialColor(_color,*this); aa.requestRedraw(); return true; } default: return false; } } void Scale1DDragger::setupDefaultGeometry() { // Get the line length and direction. osg::Vec3 lineDir = _projector->getLineEnd()-_projector->getLineStart(); float lineLength = lineDir.length(); lineDir.normalize(); osg::Geode* lineGeode = new osg::Geode; // Create a line. { osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(2); (*vertices)[0] = _projector->getLineStart(); (*vertices)[1] = _projector->getLineEnd(); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2)); lineGeode->addDrawable(geometry); } // Turn of lighting for line and set line width. lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::LineWidth* linewidth = new osg::LineWidth(); linewidth->setWidth(2.0f); lineGeode->getOrCreateStateSet()->setAttributeAndModes(linewidth, osg::StateAttribute::ON); // Add line and cones to the scene. addChild(lineGeode); // Create a left box. { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box(_projector->getLineStart(), 0.05 * lineLength))); addChild(geode); setLeftHandleNode(*geode); } // Create a right box. { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box(_projector->getLineEnd(), 0.05 * lineLength))); addChild(geode); setRightHandleNode(*geode); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/RotateCylinderDragger.cpp0000644000175000017500000001702613151044751027613 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include using namespace osgManipulator; namespace { //------------------------------------------------------------------------------ osg::Geometry* createDiskGeometry(float radius, float offset, float z, unsigned int numSegments ) { const float angleDelta = 2.0f*osg::PI/float(numSegments); const unsigned int numPoints = (numSegments+1) * 2; float angle = 0.0f; osg::Vec3Array* vertexArray = new osg::Vec3Array(numPoints); osg::Vec3Array* normalArray = new osg::Vec3Array(numPoints); unsigned int p = 0; for(unsigned int i = 0; i < numSegments; ++i,angle+=angleDelta) { float c = cosf(angle); float s = sinf(angle); // Outer point (*vertexArray)[p].set(radius*c, radius*s, z); (*normalArray)[p].set(0.0, 0.0, -1.0); ++p; // Inner point (*vertexArray)[p].set((radius-offset)*c, (radius-offset)*s, z); (*normalArray)[p].set(0.0, 0.0, -1.0); ++p; } // do last points by hand to ensure no round off errors. (*vertexArray)[p] = (*vertexArray)[0]; (*normalArray)[p] = (*normalArray)[0]; ++p; (*vertexArray)[p] = (*vertexArray)[1]; (*normalArray)[p] = (*normalArray)[1]; osg::Geometry* geometry = new osg::Geometry; geometry->setVertexArray(vertexArray); geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size())); return geometry; } } RotateCylinderDragger::RotateCylinderDragger() { _projector = new CylinderPlaneProjector(); setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } RotateCylinderDragger::~RotateCylinderDragger() { } bool RotateCylinderDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; switch (ea.getEventType()) { // Pick start. case (osgGA::GUIEventAdapter::PUSH): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::NodePath nodePathToRoot; computeNodePathToRoot(*this,nodePathToRoot); osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot); _projector->setLocalToWorld(localToWorld); _startLocalToWorld = _projector->getLocalToWorld(); _startWorldToLocal = _projector->getWorldToLocal(); if (_projector->isPointInFront(pointer, _startLocalToWorld)) _projector->setFront(true); else _projector->setFront(false); osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new Rotate3DCommand(); cmd->setStage(MotionCommand::START); cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld,_startWorldToLocal); // Dispatch command. dispatch(*cmd); // Set color to pick color. setMaterialColor(_pickColor,*this); _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld(); _prevRotation = osg::Quat(); aa.requestRedraw(); } return true; } // Pick move. case (osgGA::GUIEventAdapter::DRAG): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::Matrix localToWorld = osg::Matrix(_prevRotation) * _startLocalToWorld; _projector->setLocalToWorld(localToWorld); osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { osg::Vec3d prevProjectedPoint = _prevWorldProjPt * _projector->getWorldToLocal(); osg::Quat deltaRotation = _projector->getRotation(prevProjectedPoint, projectedPoint); osg::Quat rotation = deltaRotation * _prevRotation; // Generate the motion command. osg::ref_ptr cmd = new Rotate3DCommand(); cmd->setStage(MotionCommand::MOVE); cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld,_startWorldToLocal); cmd->setRotation(rotation); // Dispatch command. dispatch(*cmd); _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld(); _prevRotation = rotation; aa.requestRedraw(); } return true; } // Pick finish. case (osgGA::GUIEventAdapter::RELEASE): { osg::ref_ptr cmd = new Rotate3DCommand(); cmd->setStage(MotionCommand::FINISH); cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld,_startWorldToLocal); // Dispatch command. dispatch(*cmd); // Reset color. setMaterialColor(_color,*this); aa.requestRedraw(); return true; } default: return false; } } void RotateCylinderDragger::setupDefaultGeometry() { osg::Geode* geode = new osg::Geode; { osg::TessellationHints* hints = new osg::TessellationHints; hints->setCreateTop(false); hints->setCreateBottom(false); hints->setCreateBackFace(false); float radius = 1.0f; float height = 0.1f; float thickness = 0.1f; // outer cylinder osg::Cylinder* cylinder = new osg::Cylinder; cylinder->setHeight(height); cylinder->setRadius(radius); osg::ShapeDrawable* cylinderDrawable = new osg::ShapeDrawable(cylinder, hints); geode->addDrawable(cylinderDrawable); // inner cylinder osg::Cylinder* cylinder1 = const_cast(_projector->getCylinder()); cylinder1->setHeight(height); cylinder1->setRadius(radius-thickness); osg::ShapeDrawable* cylinderDrawable1 = new osg::ShapeDrawable(cylinder1, hints); geode->addDrawable(cylinderDrawable1); // top geode->addDrawable(createDiskGeometry(radius, thickness, height/2, 100)); // bottom geode->addDrawable(createDiskGeometry(radius, thickness, -height/2, 100)); } addChild(geode); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Translate2DDragger.cpp0000644000175000017500000001656513151044751027015 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include using namespace osgManipulator; Translate2DDragger::Translate2DDragger() { _projector = new PlaneProjector(osg::Plane(0.0,1.0,0.0,0.0)); _polygonOffset = new osg::PolygonOffset(-1.0f,-1.0f); setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } Translate2DDragger::Translate2DDragger(const osg::Plane& plane) { _projector = new PlaneProjector(plane); _polygonOffset = new osg::PolygonOffset(-1.0f,-1.0f); setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } Translate2DDragger::~Translate2DDragger() { } bool Translate2DDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; switch (ea.getEventType()) { // Pick start. case (osgGA::GUIEventAdapter::PUSH): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::NodePath nodePathToRoot; computeNodePathToRoot(*this,nodePathToRoot); osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot); _projector->setLocalToWorld(localToWorld); if (_projector->project(pointer, _startProjectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new TranslateInPlaneCommand(_projector->getPlane()); cmd->setStage(MotionCommand::START); cmd->setReferencePoint(_startProjectedPoint); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Set color to pick color. setMaterialColor(_pickColor,*this); getOrCreateStateSet()->setAttributeAndModes(_polygonOffset.get(), osg::StateAttribute::ON); aa.requestRedraw(); } return true; } // Pick move. case (osgGA::GUIEventAdapter::DRAG): { osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new TranslateInPlaneCommand(_projector->getPlane()); cmd->setStage(MotionCommand::MOVE); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); cmd->setTranslation(projectedPoint - _startProjectedPoint); cmd->setReferencePoint(_startProjectedPoint); // Dispatch command. dispatch(*cmd); aa.requestRedraw(); } return true; } // Pick finish. case (osgGA::GUIEventAdapter::RELEASE): { osg::ref_ptr cmd = new TranslateInPlaneCommand(_projector->getPlane()); cmd->setStage(MotionCommand::FINISH); cmd->setReferencePoint(_startProjectedPoint); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Reset color. setMaterialColor(_color,*this); getOrCreateStateSet()->removeAttribute(_polygonOffset.get()); aa.requestRedraw(); return true; } default: return false; } } void Translate2DDragger::setupDefaultGeometry() { // Create a line. osg::Geode* lineGeode = new osg::Geode; { osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(2); (*vertices)[0] = osg::Vec3(0.0f,0.0f,-0.5f); (*vertices)[1] = osg::Vec3(0.0f,0.0f,0.5f); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2)); lineGeode->addDrawable(geometry); } // Turn of lighting for line and set line width. osg::LineWidth* linewidth = new osg::LineWidth(); linewidth->setWidth(2.0f); lineGeode->getOrCreateStateSet()->setAttributeAndModes(linewidth, osg::StateAttribute::ON); lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::Geode* geode = new osg::Geode; // Create left cone. { osg::Cone* cone = new osg::Cone (osg::Vec3(0.0f, 0.0f, -0.5f), 0.025f, 0.10f); osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f,0.0f,-1.0f), osg::Vec3(0.0f, 0.0f, 1.0f)); cone->setRotation(rotation); geode->addDrawable(new osg::ShapeDrawable(cone)); } // Create right cone. { osg::Cone* cone = new osg::Cone (osg::Vec3(0.0f, 0.0f, 0.5f), 0.025f, 0.10f); geode->addDrawable(new osg::ShapeDrawable(cone)); } // Create an invisible cylinder for picking the line. { osg::Cylinder* cylinder = new osg::Cylinder (osg::Vec3(0.0f,0.0f,0.0f), 0.015f, 1.0f); osg::Drawable* drawable = new osg::ShapeDrawable(cylinder); setDrawableToAlwaysCull(*drawable); geode->addDrawable(drawable); } // MatrixTransform to rotate the geometry according to the normal of the plane. osg::MatrixTransform* xform = new osg::MatrixTransform; // Create an arrow in the X axis. { osg::MatrixTransform* arrow = new osg::MatrixTransform; arrow->addChild(lineGeode); arrow->addChild(geode); // Rotate X-axis arrow appropriately. osg::Quat rotation; rotation.makeRotate(osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 1.0f)); arrow->setMatrix(osg::Matrix(rotation)); xform->addChild(arrow); } // Create an arrow in the Z axis. { osg::Group* arrow = new osg::Group; arrow->addChild(lineGeode); arrow->addChild(geode); xform->addChild(arrow); } // Rotate the xform so that the geometry lies on the plane. { osg::Vec3 normal = _projector->getPlane().getNormal(); normal.normalize(); osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 1.0f, 0.0f), normal); xform->setMatrix(osg::Matrix(rotation)); } addChild(xform); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Command.cpp0000644000175000017500000000770513151044751024750 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include using namespace osgManipulator; /////////////////////////////////////////////////////////////////////////////// // // Motion Command base class. // MotionCommand::MotionCommand() : _stage(NONE) { } MotionCommand::~MotionCommand() { } /////////////////////////////////////////////////////////////////////////////// // // Translate in line command. // TranslateInLineCommand::TranslateInLineCommand() { _line = new osg::LineSegment; } TranslateInLineCommand::TranslateInLineCommand(const osg::LineSegment::vec_type& s, const osg::LineSegment::vec_type& e) { _line = new osg::LineSegment(s,e); } TranslateInLineCommand::~TranslateInLineCommand() { } MotionCommand* TranslateInLineCommand::createCommandInverse() { osg::ref_ptr inverse = new TranslateInLineCommand(); *inverse = *this; inverse->setTranslation(-_translation); return inverse.release(); } /////////////////////////////////////////////////////////////////////////////// // // Translate in plane command. // TranslateInPlaneCommand::TranslateInPlaneCommand() { } TranslateInPlaneCommand::TranslateInPlaneCommand(const osg::Plane& plane) : _plane(plane) { } TranslateInPlaneCommand::~TranslateInPlaneCommand() { } MotionCommand* TranslateInPlaneCommand::createCommandInverse() { osg::ref_ptr inverse = new TranslateInPlaneCommand(); *inverse = *this; inverse->setTranslation(-_translation); return inverse.release(); } /////////////////////////////////////////////////////////////////////////////// // // Scale 1D command. // Scale1DCommand::Scale1DCommand() : _scale(1.0) { } Scale1DCommand::~Scale1DCommand() { } MotionCommand* Scale1DCommand::createCommandInverse() { osg::ref_ptr inverse = new Scale1DCommand(); *inverse = *this; if (_scale) inverse->setScale(1.0/_scale); return inverse.release(); } /////////////////////////////////////////////////////////////////////////////// // // Scale 2D command. // Scale2DCommand::Scale2DCommand() : _scale(1.0,1.0) { } Scale2DCommand::~Scale2DCommand() { } MotionCommand* Scale2DCommand::createCommandInverse() { osg::ref_ptr inverse = new Scale2DCommand(); *inverse = *this; if (_scale[0] && _scale[1]) inverse->setScale(osg::Vec2(1.0/_scale[0],1.0/_scale[1])); return inverse.release(); } /////////////////////////////////////////////////////////////////////////////// // // Scale uniform command. // ScaleUniformCommand::ScaleUniformCommand() : _scale(1.0) { } ScaleUniformCommand::~ScaleUniformCommand() { } MotionCommand* ScaleUniformCommand::createCommandInverse() { osg::ref_ptr inverse = new ScaleUniformCommand(); *inverse = *this; if (_scale) inverse->setScale(1.0/_scale); return inverse.release(); } /////////////////////////////////////////////////////////////////////////////// // // Rotate 3D command. // Rotate3DCommand::Rotate3DCommand() { } Rotate3DCommand::~Rotate3DCommand() { } MotionCommand* Rotate3DCommand::createCommandInverse() { osg::ref_ptr inverse = new Rotate3DCommand(); *inverse = *this; inverse->setRotation(_rotation.inverse()); return inverse.release(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Dragger.cpp0000644000175000017500000004561013151044751024742 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include #include using namespace osgManipulator; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // computeNodePathToRoot // void osgManipulator::computeNodePathToRoot(osg::Node& node, osg::NodePath& np) { np.clear(); osg::NodePathList nodePaths = node.getParentalNodePaths(); if (!nodePaths.empty()) { np = nodePaths.front(); if (nodePaths.size()>1) { OSG_NOTICE<<"osgManipulator::computeNodePathToRoot(,) taking first parent path, ignoring others."<getMatrix(); // Get the LocalToWorld and WorldToLocal matrix for this node. osg::NodePath nodePathToRoot; computeNodePathToRoot(*_transform,nodePathToRoot); _localToWorld = osg::computeLocalToWorld(nodePathToRoot); _worldToLocal = osg::Matrix::inverse(_localToWorld); return true; } case MotionCommand::MOVE: { //OSG_NOTICE<<"MotionCommand::MOVE "<setMatrix(localMotionMatrix * _startMotionMatrix); return true; } case MotionCommand::FINISH: { return true; } case MotionCommand::NONE: default: return false; } } bool DraggerTransformCallback::receive(const TranslateInLineCommand& command) { if ((_handleCommandMask&HANDLE_TRANSLATE_IN_LINE)!=0) return receive(static_cast(command)); return false; } bool DraggerTransformCallback::receive(const TranslateInPlaneCommand& command) { if ((_handleCommandMask&HANDLE_TRANSLATE_IN_PLANE)!=0) return receive(static_cast(command)); return false; } bool DraggerTransformCallback::receive(const Scale1DCommand& command) { if ((_handleCommandMask&HANDLE_SCALED_1D)!=0) return receive(static_cast(command)); return false; } bool DraggerTransformCallback::receive(const Scale2DCommand& command) { if ((_handleCommandMask&HANDLE_SCALED_2D)!=0) return receive(static_cast(command)); return false; } bool DraggerTransformCallback::receive(const ScaleUniformCommand& command) { if ((_handleCommandMask&HANDLE_SCALED_UNIFORM)!=0) return receive(static_cast(command)); return false; } bool DraggerTransformCallback::receive(const Rotate3DCommand& command) { if ((_handleCommandMask&HANDLE_ROTATE_3D)!=0) return receive(static_cast(command)); return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // PointerInfo // PointerInfo::PointerInfo(): _nearPoint(osg::Vec3d()), _farPoint(osg::Vec3d()), _eyeDir(osg::Vec3d(0,0,1)) { _hitIter = _hitList.begin(); } bool PointerInfo::contains(const osg::Node* node) const { if (node && _hitIter!=_hitList.end()) return std::find((*_hitIter).first.begin(), (*_hitIter).first.end(), node) != (*_hitIter).first.end(); else return false; } bool PointerInfo::projectWindowXYIntoObject(const osg::Vec2d& windowCoord, osg::Vec3d& nearPoint, osg::Vec3d& farPoint) const { nearPoint = osg::Vec3d(windowCoord.x(),windowCoord.y(),0.0)*_inverseMVPW; farPoint = osg::Vec3d(windowCoord.x(),windowCoord.y(),1.0)*_inverseMVPW; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Dragger // Dragger::Dragger() : _handleEvents(false), _draggerActive(false), _activationModKeyMask(0), _activationMouseButtonMask(0), _activationKeyEvent(0), _activationPermittedByModKeyMask(false), _activationPermittedByMouseButtonMask(false), _activationPermittedByKeyEvent(false), _intersectionMask(0xffffffff) { _parentDragger = this; getOrCreateStateSet()->setDataVariance(osg::Object::DYNAMIC); _selfUpdater = new DraggerTransformCallback(this); } Dragger::Dragger(const Dragger& rhs, const osg::CopyOp& copyop): osg::MatrixTransform(rhs, copyop), _handleEvents(rhs._handleEvents), _draggerActive(false), _activationModKeyMask(rhs._activationModKeyMask), _activationMouseButtonMask(rhs._activationMouseButtonMask), _activationKeyEvent(rhs._activationKeyEvent), _activationPermittedByModKeyMask(false), _activationPermittedByMouseButtonMask(false), _activationPermittedByKeyEvent(false), _intersectionMask(0xffffffff) { } Dragger::~Dragger() { } bool Dragger::inverted() const { osg::Vec3d xAxis(_matrix(0,0), _matrix(1,0), _matrix(2,0)); osg::Vec3d yAxis(_matrix(0,1), _matrix(1,1), _matrix(2,1)); osg::Vec3d zAxis(_matrix(0,2), _matrix(1,2), _matrix(2,2)); double volume = (xAxis^yAxis)*zAxis; return volume<0.0; } void Dragger::applyAppropriateFrontFace(osg::StateSet* ss) const { osg::StateAttribute* sa = ss->getAttribute(osg::StateAttribute::FRONTFACE); osg::FrontFace* ff = dynamic_cast(sa); if (!ff) { ff = new osg::FrontFace; ss->setAttribute(ff); } ff->setMode( inverted() ? osg::FrontFace::CLOCKWISE : osg::FrontFace::COUNTER_CLOCKWISE); } void Dragger::setHandleEvents(bool flag) { if (_handleEvents == flag) return; _handleEvents = flag; // update the number of children that require an event traversal to make sure this dragger receives events. if (_handleEvents) setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()+1); else if (getNumChildrenRequiringEventTraversal()>=1) setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()-1); } void Dragger::addConstraint(Constraint* constraint) { // check to make sure constaint hasn't already been attached. for(Constraints::iterator itr = _constraints.begin(); itr != _constraints.end(); ++itr) { if (*itr == constraint) return; } _constraints.push_back(constraint); } void Dragger::removeConstraint(Constraint* constraint) { for(Constraints::iterator itr = _constraints.begin(); itr != _constraints.end(); ) { if (*itr == constraint) { _constraints.erase(itr); return; } else { ++itr; } } } void Dragger::addTransformUpdating(osg::MatrixTransform* transform, int handleCommandMask) { addDraggerCallback(new DraggerTransformCallback(transform, handleCommandMask)); } void Dragger::removeTransformUpdating(osg::MatrixTransform* transform) { for(Dragger::DraggerCallbacks::iterator itr = _draggerCallbacks.begin(); itr != _draggerCallbacks.end(); ) { DraggerCallback* dc = itr->get(); DraggerTransformCallback* dtc = dynamic_cast(dc); if (dtc && dtc->getTransform()==transform) { itr = _draggerCallbacks.erase(itr); } else { ++itr; } } } void Dragger::addDraggerCallback(DraggerCallback* dc) { for(DraggerCallbacks::iterator itr = _draggerCallbacks.begin(); itr != _draggerCallbacks.end(); ++itr) { if (*itr == dc) return; } _draggerCallbacks.push_back(dc); } void Dragger::removeDraggerCallback(DraggerCallback* dc) { for(Dragger::DraggerCallbacks::iterator itr = _draggerCallbacks.begin(); itr != _draggerCallbacks.end(); ) { if (dc==itr->get()) { itr = _draggerCallbacks.erase(itr); } else { ++itr; } } } void Dragger::traverse(osg::NodeVisitor& nv) { if (_handleEvents && nv.getVisitorType()==osg::NodeVisitor::EVENT_VISITOR) { osgGA::EventVisitor* ev = dynamic_cast(&nv); if (ev) { for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin(); itr != ev->getEvents().end(); ++itr) { osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter(); if (ea && handle(*ea, *(ev->getActionAdapter()))) ea->setHandled(true); } } return; } MatrixTransform::traverse(nv); } bool Dragger::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { if (ea.getHandled()) return false; osgViewer::View* view = dynamic_cast(&aa); if (!view) return false; bool handled = false; bool activationPermitted = true; if (_activationModKeyMask!=0 || _activationMouseButtonMask!=0 || _activationKeyEvent!=0) { _activationPermittedByModKeyMask = (_activationModKeyMask!=0) ? ((ea.getModKeyMask() & _activationModKeyMask)!=0) : false; _activationPermittedByMouseButtonMask = (_activationMouseButtonMask!=0) ? ((ea.getButtonMask() & _activationMouseButtonMask)!=0) : false; if (_activationKeyEvent!=0) { switch (ea.getEventType()) { case osgGA::GUIEventAdapter::KEYDOWN: { if (ea.getKey()==_activationKeyEvent) _activationPermittedByKeyEvent = true; break; } case osgGA::GUIEventAdapter::KEYUP: { if (ea.getKey()==_activationKeyEvent) _activationPermittedByKeyEvent = false; break; } default: break; } } activationPermitted = _activationPermittedByModKeyMask || _activationPermittedByMouseButtonMask || _activationPermittedByKeyEvent; } if (activationPermitted || _draggerActive) { switch (ea.getEventType()) { case osgGA::GUIEventAdapter::PUSH: { osgUtil::LineSegmentIntersector::Intersections intersections; _pointer.reset(); if (view->computeIntersections(ea ,intersections, _intersectionMask)) { for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin(); hitr != intersections.end(); ++hitr) { _pointer.addIntersection(hitr->nodePath, hitr->getLocalIntersectPoint()); } for (osg::NodePath::iterator itr = _pointer._hitList.front().first.begin(); itr != _pointer._hitList.front().first.end(); ++itr) { osgManipulator::Dragger* dragger = dynamic_cast(*itr); if (dragger) { if (dragger==this) { osg::Camera *rootCamera = view->getCamera(); osg::NodePath nodePath = _pointer._hitList.front().first; osg::NodePath::reverse_iterator ritr; for(ritr = nodePath.rbegin(); ritr != nodePath.rend(); ++ritr) { osg::Camera* camera = dynamic_cast(*ritr); if (camera && (camera->getReferenceFrame()!=osg::Transform::RELATIVE_RF || camera->getParents().empty())) { rootCamera = camera; break; } } _pointer.setCamera(rootCamera); _pointer.setMousePosition(ea.getX(), ea.getY()); if(dragger->handle(_pointer, ea, aa)) { dragger->setDraggerActive(true); handled = true; } } } } } break; } case osgGA::GUIEventAdapter::DRAG: case osgGA::GUIEventAdapter::RELEASE: { if (_draggerActive) { _pointer._hitIter = _pointer._hitList.begin(); // _pointer.setCamera(view->getCamera()); _pointer.setMousePosition(ea.getX(), ea.getY()); if(handle(_pointer, ea, aa)) { handled = true; } } break; } default: break; } if (_draggerActive && ea.getEventType() == osgGA::GUIEventAdapter::RELEASE) { setDraggerActive(false); _pointer.reset(); } } return handled; } bool Dragger::receive(const MotionCommand& command) { if (_selfUpdater.valid()) return _selfUpdater->receive(command); else return false; } void Dragger::dispatch(MotionCommand& command) { // apply any constraints for(Constraints::iterator itr = _constraints.begin(); itr != _constraints.end(); ++itr) { command.accept(*(*itr)); } // apply any constraints of parent dragger. if (getParentDragger()!=this) { for(Constraints::iterator itr = getParentDragger()->getConstraints().begin(); itr != getParentDragger()->getConstraints().end(); ++itr) { command.accept(*(*itr)); } } // move self getParentDragger()->receive(command); // pass on movement to any dragger callbacks for(DraggerCallbacks::iterator itr = getParentDragger()->getDraggerCallbacks().begin(); itr != getParentDragger()->getDraggerCallbacks().end(); ++itr) { command.accept(*(*itr)); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // CompositeDragger // CompositeDragger::CompositeDragger(const CompositeDragger& rhs, const osg::CopyOp& copyop): Dragger(rhs, copyop) { OSG_NOTICE<<"CompositeDragger::CompositeDragger(const CompositeDragger& rhs, const osg::CopyOp& copyop) not Implemented yet."<handle(pi, ea, aa)) return true; } return false; } bool CompositeDragger::containsDragger( const Dragger* dragger ) const { for (DraggerList::const_iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr) { if (itr->get() == dragger) return true; } return false; } CompositeDragger::DraggerList::iterator CompositeDragger::findDragger( const Dragger* dragger ) { for (DraggerList::iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr) { if (itr->get() == dragger) return itr; } return _draggerList.end(); } bool CompositeDragger::addDragger(Dragger *dragger) { if (dragger && !containsDragger(dragger)) { _draggerList.push_back(dragger); return true; } else return false; } bool CompositeDragger::removeDragger(Dragger *dragger) { DraggerList::iterator itr = findDragger(dragger); if (itr != _draggerList.end()) { _draggerList.erase(itr); return true; } else return false; } void CompositeDragger::setParentDragger(Dragger* dragger) { for (DraggerList::iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr) { (*itr)->setParentDragger(dragger); } Dragger::setParentDragger(dragger); } void CompositeDragger::setIntersectionMask(osg::Node::NodeMask intersectionMask) { Dragger::setIntersectionMask(intersectionMask); for (DraggerList::iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr) { (*itr)->setIntersectionMask(intersectionMask); } } class ForceCullCallback : public osg::Drawable::CullCallback { public: virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const { return true; } }; void osgManipulator::setDrawableToAlwaysCull(osg::Drawable& drawable) { ForceCullCallback* cullCB = new ForceCullCallback; drawable.setCullCallback (cullCB); } void osgManipulator::setMaterialColor(const osg::Vec4& color, osg::Node& node) { osg::Material* mat = dynamic_cast(node.getOrCreateStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); if (! mat) { mat = new osg::Material; mat->setDataVariance(osg::Object::DYNAMIC); node.getOrCreateStateSet()->setAttribute(mat); } mat->setDiffuse(osg::Material::FRONT_AND_BACK, color); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TabBoxTrackballDragger.cpp0000644000175000017500000000272713151044751027664 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include #include #include using namespace osgManipulator; TabBoxTrackballDragger::TabBoxTrackballDragger() { _trackballDragger = new TrackballDragger(true); addChild(_trackballDragger.get()); addDragger(_trackballDragger.get()); _tabBoxDragger = new TabBoxDragger(); addChild(_tabBoxDragger.get()); addDragger(_tabBoxDragger.get()); setParentDragger(getParentDragger()); } TabBoxTrackballDragger::~TabBoxTrackballDragger() { } void TabBoxTrackballDragger::setupDefaultGeometry() { _trackballDragger->setupDefaultGeometry(); _tabBoxDragger->setupDefaultGeometry(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TranslatePlaneDragger.cpp0000644000175000017500000000701313151044751027573 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include #include #include using namespace osgManipulator; TranslatePlaneDragger::TranslatePlaneDragger() : _usingTranslate1DDragger(false) { _translate2DDragger = new Translate2DDragger(); _translate2DDragger->setColor(osg::Vec4(0.7f, 0.7f, 0.7f, 1.0f)); addChild(_translate2DDragger.get()); addDragger(_translate2DDragger.get()); _translate1DDragger = new Translate1DDragger(osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(0.0f,1.0f,0.0f)); _translate1DDragger->setCheckForNodeInNodePath(false); addChild(_translate1DDragger.get()); addDragger(_translate1DDragger.get()); setParentDragger(getParentDragger()); } TranslatePlaneDragger::~TranslatePlaneDragger() { } bool TranslatePlaneDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; if ((ea.getButtonMask() & osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) && ea.getEventType() == osgGA::GUIEventAdapter::PUSH) _usingTranslate1DDragger = true; bool handled = false; if (_usingTranslate1DDragger) { if (_translate1DDragger->handle(pointer, ea, aa)) handled = true; } else { if (_translate2DDragger->handle(pointer, ea, aa)) handled = true; } if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE) _usingTranslate1DDragger = false; return handled; } void TranslatePlaneDragger::setupDefaultGeometry() { // Create a polygon. { osg::Geode* geode = new osg::Geode; osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(4); (*vertices)[0] = osg::Vec3(-0.5,0.0,0.5); (*vertices)[1] = osg::Vec3(-0.5,0.0,-0.5); (*vertices)[2] = osg::Vec3(0.5,0.0,-0.5); (*vertices)[3] = osg::Vec3(0.5,0.0,0.5); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,vertices->size())); osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0,1.0,0.0)); geometry->setNormalArray(normals, osg::Array::BIND_OVERALL); geode->addDrawable(geometry); osg::PolygonMode* polymode = new osg::PolygonMode; polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE); geode->getOrCreateStateSet()->setAttributeAndModes(polymode,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); _translate2DDragger->addChild(geode); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/ScaleAxisDragger.cpp0000644000175000017500000000755113151044751026541 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include using namespace osgManipulator; ScaleAxisDragger::ScaleAxisDragger() { _xDragger = new osgManipulator::Scale1DDragger(); addChild(_xDragger.get()); addDragger(_xDragger.get()); _yDragger = new osgManipulator::Scale1DDragger(); addChild(_yDragger.get()); addDragger(_yDragger.get()); _zDragger = new osgManipulator::Scale1DDragger(); addChild(_zDragger.get()); addDragger(_zDragger.get()); _axisLineWidth = 2.0f; _boxSize = 0.05f; setParentDragger(getParentDragger()); } ScaleAxisDragger::~ScaleAxisDragger() { } void ScaleAxisDragger::setupDefaultGeometry() { // Create a line. _lineGeode = new osg::Geode; { osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(2); (*vertices)[0] = osg::Vec3(0.0f,0.0f,0.0f); (*vertices)[1] = osg::Vec3(1.0f,0.0f,0.0f); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2)); _lineGeode->addDrawable(geometry); } // Turn of lighting for line and set line width. { _lineWidth = new osg::LineWidth(); _lineWidth->setWidth(_axisLineWidth); _lineGeode->getOrCreateStateSet()->setAttributeAndModes(_lineWidth.get(), osg::StateAttribute::ON); _lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); } // Add line to all the individual 1D draggers. _xDragger->addChild(_lineGeode.get()); _yDragger->addChild(_lineGeode.get()); _zDragger->addChild(_lineGeode.get()); osg::Geode* geode = new osg::Geode; // Create a box. _box = new osg::Box(osg::Vec3(1.0f,0.0f,0.0f), _boxSize); geode->addDrawable(new osg::ShapeDrawable(_box.get())); // This ensures correct lighting for scaled draggers. #if !defined(OSG_GLES2_AVAILABLE) geode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); #endif // Add geode to all 1D draggers. _xDragger->addChild(geode); _yDragger->addChild(geode); _zDragger->addChild(geode); // Rotate Z-axis dragger appropriately. { osg::Quat rotation; rotation.makeRotate(osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 1.0f)); _zDragger->setMatrix(osg::Matrix(rotation)); } // Rotate Y-axis dragger appropriately. { osg::Quat rotation; rotation.makeRotate(osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); _yDragger->setMatrix(osg::Matrix(rotation)); } // Send different colors for each dragger. _xDragger->setColor(osg::Vec4(1.0f,0.0f,0.0f,1.0f)); _yDragger->setColor(osg::Vec4(0.0f,1.0f,0.0f,1.0f)); _zDragger->setColor(osg::Vec4(0.0f,0.0f,1.0f,1.0f)); } void ScaleAxisDragger::setAxisLineWidth(float linePixelWidth) { _axisLineWidth = linePixelWidth; if (_lineWidth.valid()) _lineWidth->setWidth(linePixelWidth); } void ScaleAxisDragger::setBoxSize(float size) { _boxSize = size; if (_box.valid()) _box->setHalfLengths(osg::Vec3(size * 0.5f, size * 0.5f, size * 0.5f)); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/CMakeLists.txt0000644000175000017500000000330413151044751025415 0ustar albertoalberto IF(DYNAMIC_OPENSCENEGRAPH) ADD_DEFINITIONS(-DOSGMANIPULATOR_LIBRARY) ELSE() ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) ENDIF() SET(LIB_NAME osgManipulator) SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) SET(TARGET_H ${HEADER_PATH}/AntiSquish ${HEADER_PATH}/Command ${HEADER_PATH}/CommandManager ${HEADER_PATH}/Constraint ${HEADER_PATH}/Dragger ${HEADER_PATH}/Export ${HEADER_PATH}/Projector ${HEADER_PATH}/RotateCylinderDragger ${HEADER_PATH}/RotateSphereDragger ${HEADER_PATH}/Scale1DDragger ${HEADER_PATH}/Scale2DDragger ${HEADER_PATH}/ScaleAxisDragger ${HEADER_PATH}/Selection ${HEADER_PATH}/TabBoxDragger ${HEADER_PATH}/TabBoxTrackballDragger ${HEADER_PATH}/TabPlaneDragger ${HEADER_PATH}/TabPlaneTrackballDragger ${HEADER_PATH}/TrackballDragger ${HEADER_PATH}/Translate1DDragger ${HEADER_PATH}/Translate2DDragger ${HEADER_PATH}/TranslateAxisDragger ${HEADER_PATH}/TranslatePlaneDragger ${HEADER_PATH}/Version ) # FIXME: For OS X, need flag for Framework or dylib SET(TARGET_SRC AntiSquish.cpp Command.cpp Constraint.cpp Dragger.cpp Projector.cpp RotateCylinderDragger.cpp RotateSphereDragger.cpp Scale1DDragger.cpp Scale2DDragger.cpp ScaleAxisDragger.cpp TabBoxDragger.cpp TabBoxTrackballDragger.cpp TabPlaneDragger.cpp TabPlaneTrackballDragger.cpp TrackballDragger.cpp Translate1DDragger.cpp Translate2DDragger.cpp TranslateAxisDragger.cpp TranslatePlaneDragger.cpp Version.cpp ${OPENSCENEGRAPH_VERSIONINFO_RC} ) SET(TARGET_LIBRARIES osgViewer osgGA osgUtil osg OpenThreads ) SETUP_LIBRARY(${LIB_NAME}) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/RotateSphereDragger.cpp0000644000175000017500000001255313151044751027270 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include using namespace osgManipulator; RotateSphereDragger::RotateSphereDragger() : _prevPtOnSphere(true) { _projector = new SpherePlaneProjector(); setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); setPickColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); } RotateSphereDragger::~RotateSphereDragger() { } bool RotateSphereDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; switch (ea.getEventType()) { // Pick start. case (osgGA::GUIEventAdapter::PUSH): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::NodePath nodePathToRoot; computeNodePathToRoot(*this,nodePathToRoot); osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot); _projector->setLocalToWorld(localToWorld); _startLocalToWorld = _projector->getLocalToWorld(); _startWorldToLocal = _projector->getWorldToLocal(); if (_projector->isPointInFront(pointer, _startLocalToWorld)) _projector->setFront(true); else _projector->setFront(false); osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { // Generate the motion command. osg::ref_ptr cmd = new Rotate3DCommand(); cmd->setStage(MotionCommand::START); cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld,_startWorldToLocal); // Dispatch command. dispatch(*cmd); // Set color to pick color. setMaterialColor(_pickColor,*this); _prevRotation = osg::Quat(); _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld(); _prevPtOnSphere = _projector->isProjectionOnSphere(); aa.requestRedraw(); } return true; } // Pick move. case (osgGA::GUIEventAdapter::DRAG): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::Matrix localToWorld = osg::Matrix(_prevRotation) * _startLocalToWorld; _projector->setLocalToWorld(localToWorld); osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { osg::Vec3d prevProjectedPoint = _prevWorldProjPt * _projector->getWorldToLocal(); osg::Quat deltaRotation = _projector->getRotation(prevProjectedPoint, _prevPtOnSphere, projectedPoint, _projector->isProjectionOnSphere(),1.0f); osg::Quat rotation = deltaRotation * _prevRotation; // Generate the motion command. osg::ref_ptr cmd = new Rotate3DCommand(); cmd->setStage(MotionCommand::MOVE); cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld,_startWorldToLocal); cmd->setRotation(rotation); // Dispatch command. dispatch(*cmd); _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld(); _prevRotation = rotation; _prevPtOnSphere = _projector->isProjectionOnSphere(); aa.requestRedraw(); } return true; } // Pick finish. case (osgGA::GUIEventAdapter::RELEASE): { osg::ref_ptr cmd = new Rotate3DCommand(); cmd->setStage(MotionCommand::FINISH); cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld,_startWorldToLocal); // Dispatch command. dispatch(*cmd); // Reset color. setMaterialColor(_color,*this); aa.requestRedraw(); return true; } default: return false; } } void RotateSphereDragger::setupDefaultGeometry() { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(const_cast(_projector->getSphere()))); addChild(geode); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Projector.cpp0000644000175000017500000005206613151044751025341 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include using namespace osgManipulator; // When the squared magnitude (length2) of the cross product of 2 // angles is less than this tolerance, they are considered parallel. // osg::Vec3 a, b; (a ^ b).length2() #define CROSS_PRODUCT_ANGLE_TOLERANCE 1.0e-1 namespace { bool computeClosestPoints(const osg::LineSegment& l1, const osg::LineSegment& l2, osg::Vec3d& p1, osg::Vec3d& p2) { // Computes the closest points (p1 and p2 on line l1 and l2 respectively) between the two lines // An explanation of the algorithm can be found at // http://www.geometryalgorithms.com/Archive/algorithm_0106/algorithm_0106.htm osg::LineSegment::vec_type u = l1.end() - l1.start(); u.normalize(); osg::LineSegment::vec_type v = l2.end() - l2.start(); v.normalize(); osg::LineSegment::vec_type w0 = l1.start() - l2.start(); double a = u * u; double b = u * v; double c = v * v; double d = u * w0; double e = v * w0; double denominator = a*c - b*b; // Test if lines are parallel if (denominator == 0.0) return false; double sc = (b*e - c*d)/denominator; double tc = (a*e - b*d)/denominator; p1 = l1.start() + u * sc; p2 = l2.start() + v * tc; return true; } bool computeClosestPointOnLine(const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd, const osg::Vec3d& fromPoint, osg::Vec3d& closestPoint) { osg::Vec3d v = lineEnd - lineStart; osg::Vec3d w = fromPoint - lineStart; double c1 = w * v; double c2 = v * v; double almostZero = 0.000001; if (c2 < almostZero) return false; double b = c1 / c2; closestPoint = lineStart + v * b; return true; } bool getPlaneLineIntersection(const osg::Vec4d& plane, const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd, osg::Vec3d& isect) { const double deltaX = lineEnd.x() - lineStart.x(); const double deltaY = lineEnd.y() - lineStart.y(); const double deltaZ = lineEnd.z() - lineStart.z(); const double denominator = (plane[0]*deltaX + plane[1]*deltaY + plane[2]*deltaZ); if (! denominator) return false; const double C = (plane[0]*lineStart.x() + plane[1]*lineStart.y() + plane[2]*lineStart.z() + plane[3]) / denominator; isect.x() = lineStart.x() - deltaX * C; isect.y() = lineStart.y() - deltaY * C; isect.z() = lineStart.z() - deltaZ * C; return true; } bool getSphereLineIntersection(const osg::Sphere& sphere, const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd, osg::Vec3d& frontISect, osg::Vec3d& backISect) { osg::Vec3d lineDirection = lineEnd - lineStart; lineDirection.normalize(); osg::Vec3d v = lineStart - sphere.getCenter(); double B = 2.0f * (lineDirection * v); double C = v * v - sphere.getRadius() * sphere.getRadius(); double discriminant = B * B - 4.0f * C; if (discriminant < 0.0f) // Line and sphere don't intersect. return false; double discriminantSqroot = sqrtf(discriminant); double t0 = (-B - discriminantSqroot) * 0.5f; frontISect = lineStart + lineDirection * t0; double t1 = (-B + discriminantSqroot) * 0.5f; backISect = lineStart + lineDirection * t1; return true; } bool getUnitCylinderLineIntersection(const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd, osg::Vec3d& isectFront, osg::Vec3d& isectBack) { osg::Vec3d dir = lineEnd - lineStart; dir.normalize(); double a = dir[0] * dir[0] + dir[1] * dir[1]; double b = 2.0f * (lineStart[0] * dir[0] + lineStart[1] * dir[1]); double c = lineStart[0] * lineStart[0] + lineStart[1] * lineStart[1] - 1; double d = b*b - 4*a*c; if (d < 0.0f) return false; double dSqroot = sqrtf(d); double t0, t1; if (b > 0.0f) { t0 = -(2.0f * c) / (dSqroot + b); t1 = -(dSqroot + b) / (2.0 * a); } else { t0 = (2.0f * c) / (dSqroot - b); t1 = (dSqroot - b) / (2.0 * a); } isectFront = lineStart + dir * t0; isectBack = lineStart + dir * t1; return true; } bool getCylinderLineIntersection(const osg::Cylinder& cylinder, const osg::Vec3d& lineStart, const osg::Vec3d& lineEnd, osg::Vec3d& isectFront, osg::Vec3d& isectBack) { // Compute matrix transformation that takes the cylinder to a unit cylinder with Z-axis as it's axis and // (0,0,0) as it's center. double oneOverRadius = 1.0f / cylinder.getRadius(); osg::Matrix toUnitCylInZ = osg::Matrix::translate(-cylinder.getCenter()) * osg::Matrix::scale(oneOverRadius, oneOverRadius, oneOverRadius) * osg::Matrix(cylinder.getRotation().inverse()); // Transform the lineStart and lineEnd into the unit cylinder space. osg::Vec3d unitCylLineStart = lineStart * toUnitCylInZ; osg::Vec3d unitCylLineEnd = lineEnd * toUnitCylInZ; // Intersect line with unit cylinder. osg::Vec3d unitCylIsectFront, unitCylIsectBack; if (! getUnitCylinderLineIntersection(unitCylLineStart, unitCylLineEnd, unitCylIsectFront, unitCylIsectBack)) return false; // Transform back from unit cylinder space. osg::Matrix invToUnitCylInZ(osg::Matrix::inverse(toUnitCylInZ)); isectFront = unitCylIsectFront * invToUnitCylInZ; isectBack = unitCylIsectBack * invToUnitCylInZ; return true; } osg::Vec3d getLocalEyeDirection(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld) { // To take a normal from world to local you need to transform it by the transpose of the inverse of the // world to local matrix. Pre-multiplying is equivalent to doing a post-multiplication of the transpose. osg::Vec3d localEyeDir = localToWorld * eyeDir; localEyeDir.normalize(); return localEyeDir; } osg::Plane computePlaneThruPointAndOrientedToEye(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld, const osg::Vec3d& point, bool front) { osg::Vec3d planeNormal = getLocalEyeDirection(eyeDir, localToWorld); if (! front) planeNormal = -planeNormal; osg::Plane plane; plane.set(planeNormal, point); return plane; } // Computes a plane to be used as a basis for determining a displacement. When eyeDir is close // to the cylinder axis, then the plane will be set to be perpendicular to the cylinder axis. // Otherwise it will be set to be parallel to the cylinder axis and oriented towards eyeDir. osg::Plane computeIntersectionPlane(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld, const osg::Vec3d& axisDir, const osg::Cylinder& cylinder, osg::Vec3d& planeLineStart, osg::Vec3d& planeLineEnd, bool& parallelPlane, bool front) { osg::Plane plane; osg::Vec3d unitAxisDir = axisDir; unitAxisDir.normalize(); osg::Vec3d perpDir = unitAxisDir ^ getLocalEyeDirection(eyeDir, localToWorld); // Check to make sure eye and cylinder axis are not too close if(perpDir.length2() < CROSS_PRODUCT_ANGLE_TOLERANCE) { // Too close, so instead return plane perpendicular to cylinder axis. plane.set(unitAxisDir, cylinder.getCenter()); parallelPlane = false; return plane; } // Otherwise compute plane along axisDir oriented towards eye osg::Vec3d planeDir = perpDir ^ axisDir; planeDir.normalize(); if (! front) planeDir = -planeDir; osg::Vec3d planePoint = planeDir * cylinder.getRadius() + axisDir; plane.set(planeDir, planePoint); planeLineStart = planePoint; planeLineEnd = planePoint + axisDir; parallelPlane = true; return plane; } } // namespace Projector::Projector() : _worldToLocalDirty(false) { } Projector::~Projector() { } LineProjector::LineProjector() { _line = new osg::LineSegment(osg::LineSegment::vec_type(0.0,0.0,0.0), osg::LineSegment::vec_type(1.0,0.0,0.0)); } LineProjector::LineProjector(const osg::LineSegment::vec_type& s, const osg::LineSegment::vec_type& e) { _line = new osg::LineSegment(s,e); } LineProjector::~LineProjector() { } bool LineProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const { if (!_line->valid()) { OSG_WARN << "Warning: Invalid line set. LineProjector::project() failed."< objectLine = new osg::LineSegment; objectLine->mult(*_line, getLocalToWorld()); // Get the near and far points for the mouse point. osg::Vec3d nearPoint, farPoint; pi.getNearFarPoints(nearPoint,farPoint); osg::ref_ptr pointerLine = new osg::LineSegment(nearPoint,farPoint); osg::Vec3d closestPtLine, closestPtProjWorkingLine; if (! computeClosestPoints(*objectLine, *pointerLine, closestPtLine, closestPtProjWorkingLine)) return false; osg::Vec3d localClosestPtLine = closestPtLine * getWorldToLocal(); projectedPoint = localClosestPtLine; return true; } PlaneProjector::PlaneProjector() { } PlaneProjector::PlaneProjector(const osg::Plane& plane) { _plane = plane; } PlaneProjector::~PlaneProjector() { } bool PlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const { if (!_plane.valid()) { OSG_WARN << "Warning: Invalid plane set. PlaneProjector::project() failed."<< std::endl; return false; } // Get the near and far points for the mouse point. osg::Vec3d nearPoint, farPoint; pi.getNearFarPoints(nearPoint,farPoint); // Transform these points into local coordinates. osg::Vec3d objectNearPoint, objectFarPoint; objectNearPoint = nearPoint * getWorldToLocal(); objectFarPoint = farPoint * getWorldToLocal(); // Find the intersection of the plane with the line (formed by the near and far points in local coordinates). return getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, projectedPoint); } SphereProjector::SphereProjector() : _sphere(new osg::Sphere), _front(true) { } SphereProjector::SphereProjector(osg::Sphere* sphere) : _sphere(sphere), _front(true) { } SphereProjector::~SphereProjector() { } bool SphereProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const { if (!_sphere->valid()) { OSG_WARN << "Warning: Invalid sphere. SphereProjector::project() failed." << std::endl; return false; } // Get the near and far points for the mouse point. osg::Vec3d nearPoint, farPoint; pi.getNearFarPoints(nearPoint,farPoint); // Transform these points into local coordinates. osg::Vec3d objectNearPoint, objectFarPoint; objectNearPoint = nearPoint * getWorldToLocal(); objectFarPoint = farPoint * getWorldToLocal(); // Find the intersection of the sphere with the line. osg::Vec3d dontCare; if (_front) return getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, projectedPoint, dontCare); return getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, dontCare, projectedPoint); } bool SphereProjector::isPointInFront(const PointerInfo& pi, const osg::Matrix& localToWorld) const { osg::Vec3d centerToPoint = getSphere()->getCenter() - pi.getLocalIntersectPoint(); if (centerToPoint * getLocalEyeDirection(pi.getEyeDir(), localToWorld) < 0.0) return false; return true; } SpherePlaneProjector::SpherePlaneProjector() { } SpherePlaneProjector::SpherePlaneProjector(osg::Sphere* sphere) : SphereProjector(sphere) { } SpherePlaneProjector::~SpherePlaneProjector() { } osg::Quat SpherePlaneProjector::getRotation(const osg::Vec3d& p1, bool p1OnSphere, const osg::Vec3d& p2, bool p2OnSphere, float radialFactor) const { if (p1OnSphere && p2OnSphere) { osg::Quat rotation; if (_front) rotation.makeRotate(p1 - getSphere()->getCenter(), p2 - getSphere()->getCenter()); else rotation.makeRotate(p2 - getSphere()->getCenter(), p1 - getSphere()->getCenter()); return rotation; } else if (!p1OnSphere && !p2OnSphere) { osg::Quat rotation; rotation.makeRotate(p1 - getSphere()->getCenter(), p2 - getSphere()->getCenter()); osg::Vec3d axis; double angle; rotation.getRotate(angle, axis); osg::Vec3d realAxis; if (axis * _plane.getNormal() > 0.0f) realAxis = _plane.getNormal(); else realAxis = - _plane.getNormal(); osg::Quat rollRotation(angle, realAxis); osg::Vec3d diff1 = p1 - getSphere()->getCenter(); osg::Vec3d diff2 = p2 - getSphere()->getCenter(); double d = diff2.length() - diff1.length(); double theta = d / getSphere()->getRadius(); if (fabs(theta) < 0.000001 || fabs(theta) > 1.0) return rollRotation; diff1.normalize(); osg::Vec3d pullAxis = diff1 ^ _plane.getNormal(); pullAxis.normalize(); osg::Quat pullRotation(radialFactor * theta, pullAxis); osg::Quat totalRotation = pullRotation * rollRotation; return totalRotation; } else { const osg::Vec3d& planePoint = getSphere()->getCenter(); osg::Vec3d intersection, dontCare; if (p1OnSphere) getSphereLineIntersection(*getSphere(), p2, planePoint, intersection, dontCare); else getSphereLineIntersection(*getSphere(), p1, planePoint, intersection, dontCare); osg::Quat rotation; if (p1OnSphere) rotation.makeRotate(p1 - getSphere()->getCenter(), intersection - getSphere()->getCenter()); else rotation.makeRotate(intersection - getSphere()->getCenter(), p2 - getSphere()->getCenter()); return rotation; } } bool SpherePlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const { if (!_sphere->valid()) { OSG_WARN << "Warning: Invalid sphere. SpherePlaneProjector::project() failed." << std::endl; return false; } // Get the near and far points for the mouse point. osg::Vec3d nearPoint, farPoint; pi.getNearFarPoints(nearPoint,farPoint); // Transform these points into local coordinates. osg::Vec3d objectNearPoint, objectFarPoint; objectNearPoint = nearPoint * getWorldToLocal(); objectFarPoint = farPoint * getWorldToLocal(); // Find the intersection of the sphere with the line. osg::Vec3d sphereIntersection, dontCare; bool hitSphere = false; if (_front) hitSphere = getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, sphereIntersection, dontCare); else hitSphere = getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, dontCare, sphereIntersection); // Compute plane oriented to the eye. _plane = computePlaneThruPointAndOrientedToEye(pi.getEyeDir(), getLocalToWorld(), getSphere()->getCenter(), _front); // Find the intersection on the plane. osg::Vec3d planeIntersection; if (hitSphere) { if (! getPlaneLineIntersection(_plane.asVec4(), sphereIntersection, sphereIntersection + _plane.getNormal(), planeIntersection)) return false; } else { if (! getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, planeIntersection)) return false; } // Distance from the plane intersection point to the center of the sphere. double dist = (planeIntersection - getSphere()->getCenter()).length(); // If the distance is less that the sphere radius choose the sphere intersection else choose // the plane intersection. if (dist < getSphere()->getRadius()) { if (! hitSphere) return false; projectedPoint = sphereIntersection; _onSphere = true; } else { projectedPoint = planeIntersection; _onSphere = false; } return true; } CylinderProjector::CylinderProjector() : _cylinder(new osg::Cylinder()), _cylinderAxis(0.0,0.0,1.0), _front(true) { } CylinderProjector::CylinderProjector(osg::Cylinder* cylinder) : _front(true) { setCylinder(cylinder); } CylinderProjector::~CylinderProjector() { } bool CylinderProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const { if (!_cylinder.valid()) { OSG_WARN << "Warning: Invalid cylinder. CylinderProjector::project() failed." << std::endl; return false; } // Get the near and far points for the mouse point. osg::Vec3d nearPoint, farPoint; pi.getNearFarPoints(nearPoint,farPoint); // Transform these points into local coordinates. osg::Vec3d objectNearPoint, objectFarPoint; objectNearPoint = nearPoint * getWorldToLocal(); objectFarPoint = farPoint * getWorldToLocal(); // Find the intersection of the sphere with the line. osg::Vec3d dontCare; return getCylinderLineIntersection(*_cylinder, objectNearPoint, objectFarPoint, projectedPoint, dontCare); } bool CylinderProjector::isPointInFront(const PointerInfo& pi, const osg::Matrix& localToWorld) const { osg::Vec3d closestPointOnAxis; computeClosestPointOnLine(getCylinder()->getCenter(), getCylinder()->getCenter() + _cylinderAxis, pi.getLocalIntersectPoint(), closestPointOnAxis); osg::Vec3d perpPoint = pi.getLocalIntersectPoint() - closestPointOnAxis; if (perpPoint * getLocalEyeDirection(pi.getEyeDir(), localToWorld) < 0.0) return false; return true; } CylinderPlaneProjector::CylinderPlaneProjector() { } CylinderPlaneProjector::CylinderPlaneProjector(osg::Cylinder* cylinder) : CylinderProjector(cylinder), _parallelPlane(false) { } CylinderPlaneProjector::~CylinderPlaneProjector() { } bool CylinderPlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const { if (!_cylinder.valid()) { OSG_WARN << "Warning: Invalid cylinder. CylinderProjector::project() failed." << std::endl; return false; } // Get the near and far points for the mouse point. osg::Vec3d nearPoint, farPoint; pi.getNearFarPoints(nearPoint,farPoint); // Transform these points into local coordinates. osg::Vec3d objectNearPoint, objectFarPoint; objectNearPoint = nearPoint * getWorldToLocal(); objectFarPoint = farPoint * getWorldToLocal(); // Computes either a plane parallel to cylinder axis oriented to the eye or the plane // perpendicular to the cylinder axis if the eye-cylinder angle is close. _plane = computeIntersectionPlane(pi.getEyeDir(), getLocalToWorld(), _cylinderAxis, *_cylinder, _planeLineStart, _planeLineEnd, _parallelPlane, _front); // Now find the point of intersection on our newly-calculated plane. getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, projectedPoint); return true; } osg::Quat CylinderPlaneProjector::getRotation(const osg::Vec3d& p1, const osg::Vec3d& p2) const { if(_parallelPlane) { osg::Vec3d closestPointToPlaneLine1, closestPointToPlaneLine2; computeClosestPointOnLine(_planeLineStart, _planeLineEnd, p1, closestPointToPlaneLine1); computeClosestPointOnLine(_planeLineStart, _planeLineEnd, p2, closestPointToPlaneLine2); osg::Vec3d v1 = p1 - closestPointToPlaneLine1; osg::Vec3d v2 = p2 - closestPointToPlaneLine2; osg::Vec3d diff = v2 - v1; double d = diff.length(); // The amount of rotation is inversely proportional to the size of the cylinder double angle = (getCylinder()->getRadius() == 0.0) ? 0.0 : (d / getCylinder()->getRadius()); osg::Vec3d rotAxis = _plane.getNormal() ^ v1; if (v2.length() > v1.length()) return osg::Quat(angle, rotAxis); else return osg::Quat(-angle, rotAxis); } else { osg::Vec3d v1 = p1 - getCylinder()->getCenter(); osg::Vec3d v2 = p2 - getCylinder()->getCenter(); double cosAngle = v1 * v2 / (v1.length() * v2.length()); if (cosAngle > 1.0 || cosAngle < -1.0) return osg::Quat(); double angle = acosf(cosAngle); osg::Vec3d rotAxis = v1 ^ v2; return osg::Quat(angle, rotAxis); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/AntiSquish.cpp0000644000175000017500000001156613151044751025462 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include using namespace osgManipulator; AntiSquish::AntiSquish() : _usePivot(true), _usePosition(false), _cacheDirty( true ) { } AntiSquish::AntiSquish(const osg::Vec3d& pivot) : _pivot(pivot), _usePivot(true), _usePosition(false), _cacheDirty( true ) { } AntiSquish::AntiSquish(const osg::Vec3d& pivot, const osg::Vec3d& pos) : _pivot(pivot), _usePivot(true), _position(pos), _usePosition(true), _cacheDirty( true ) { } AntiSquish::AntiSquish(const AntiSquish& pat,const osg::CopyOp& copyop) : Transform(pat,copyop), _pivot(pat._pivot), _usePivot(pat._usePivot), _position(pat._position), _usePosition(pat._usePosition), _cacheDirty(pat._cacheDirty), _cacheLocalToWorld(pat._cacheLocalToWorld), _cache(pat._cache) { } AntiSquish::~AntiSquish() { } bool AntiSquish::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const { osg::Matrix unsquishedMatrix; if ( !computeUnSquishedMatrix( unsquishedMatrix ) ) { return false; } if (_referenceFrame==RELATIVE_RF) { matrix.preMult(unsquishedMatrix); } else // absolute { matrix = unsquishedMatrix; } return true; } bool AntiSquish::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const { osg::Matrix unsquishedMatrix; if ( !computeUnSquishedMatrix( unsquishedMatrix ) ) { return false; } osg::Matrixd inverse; inverse.invert( unsquishedMatrix ); if (_referenceFrame==RELATIVE_RF) { matrix.postMult(inverse); } else // absolute { matrix = inverse; } return true; } bool AntiSquish::computeUnSquishedMatrix(osg::Matrix& unsquished) const { OpenThreads::ScopedLock lock( _cacheLock ); osg::NodePathList nodePaths = getParentalNodePaths(); if (nodePaths.empty()) return false; osg::NodePath np = nodePaths.front(); if (np.empty()) return false; // Remove the last node which is the anti squish node itself. np.pop_back(); // Get the accumulated modeling matrix. const osg::Matrix localToWorld = osg::computeLocalToWorld(np); // reuse cached value if ( !_cacheDirty && _cacheLocalToWorld==localToWorld ) { unsquished = _cache; return true; } osg::Vec3d t, s; osg::Quat r, so; localToWorld.decompose(t, r, s, so); // Let's take an average of the scale. double av = (s[0] + s[1] + s[2])/3.0; s[0] = av; s[1] = av; s[2]=av; if (av == 0) return false; // // Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position] // OR [SO]^[S][SO][R][T][LOCALTOWORLD]^ // if (_usePivot) { unsquished.postMultTranslate(-_pivot); osg::Matrix tmps, invtmps; so.get(tmps); if (!invtmps.invert(tmps)) return false; //SO^ unsquished.postMult(invtmps); //S unsquished.postMultScale(s); //SO unsquished.postMult(tmps); //R unsquished.postMultRotate(r); //T unsquished.postMultTranslate(t); osg::Matrix invltw; if (!invltw.invert(localToWorld)) return false; // LTW^ unsquished.postMult( invltw ); // Position if (_usePosition) unsquished.postMultTranslate(_position); else unsquished.postMultTranslate(_pivot); } else { osg::Matrix tmps, invtmps; so.get(tmps); if (!invtmps.invert(tmps)) return false; unsquished.postMult(invtmps); unsquished.postMultScale(s); unsquished.postMult(tmps); unsquished.postMultRotate(r); unsquished.postMultTranslate(t); osg::Matrix invltw; if (!invltw.invert(localToWorld)) return false; unsquished.postMult( invltw ); } if (unsquished.isNaN()) return false; _cache = unsquished; _cacheLocalToWorld = localToWorld; _cacheDirty = false; //As Transform::computeBounde calls us without a node-path it relies on //The cache. Hence a new _cache affects the bound. const_cast(this)->dirtyBound(); return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TabPlaneDragger.cpp0000644000175000017500000002626513151044751026356 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include #include #include #include using namespace osgManipulator; namespace { osg::Node* createHandleNode(Scale2DDragger* cornerScaleDragger, float handleScaleFactor, bool twosided) { osg::Vec3Array* vertices = new osg::Vec3Array(4); (*vertices)[0] = osg::Vec3(cornerScaleDragger->getTopLeftHandlePosition()[0],0.0,cornerScaleDragger->getTopLeftHandlePosition()[1]) * handleScaleFactor; (*vertices)[1] = osg::Vec3(cornerScaleDragger->getBottomLeftHandlePosition()[0],0.0,cornerScaleDragger->getBottomLeftHandlePosition()[1]) * handleScaleFactor; (*vertices)[2] = osg::Vec3(cornerScaleDragger->getBottomRightHandlePosition()[0],0.0,cornerScaleDragger->getBottomRightHandlePosition()[1]) * handleScaleFactor; (*vertices)[3] = osg::Vec3(cornerScaleDragger->getTopRightHandlePosition()[0],0.0,cornerScaleDragger->getTopRightHandlePosition()[1]) * handleScaleFactor; osg::Geometry* geometry = new osg::Geometry(); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,vertices->size())); osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0,1.0,0.0)); geometry->setNormalArray(normals, osg::Array::BIND_OVERALL); osg::Geode* geode = new osg::Geode; geode->setName("Dragger Handle"); geode->addDrawable(geometry); if (!twosided) { osg::CullFace* cullface = new osg::CullFace; cullface->setMode(osg::CullFace::FRONT); geode->getOrCreateStateSet()->setAttribute(cullface, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); geode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); return geode; } osg::Node* createHandleScene(const osg::Vec3& pos, osg::Node* handleNode, float handleScaleFactor) { osg::AutoTransform *at = new osg::AutoTransform; at->setPosition(pos); at->setPivotPoint(pos * handleScaleFactor); at->setAutoScaleToScreen(true); at->addChild(handleNode); AntiSquish* as = new AntiSquish; as->setPivot(pos); as->addChild(at); return as; } void createCornerScaleDraggerGeometry(Scale2DDragger* cornerScaleDragger, osg::Node* handleNode, float handleScaleFactor) { // Create a top left box. { osg::Node* handleScene = createHandleScene(osg::Vec3(cornerScaleDragger->getTopLeftHandlePosition()[0], 0.0,cornerScaleDragger->getTopLeftHandlePosition()[1]), handleNode, handleScaleFactor); cornerScaleDragger->addChild(handleScene); cornerScaleDragger->setTopLeftHandleNode(*handleScene); } // Create a bottom left box. { osg::Node* handleScene = createHandleScene(osg::Vec3(cornerScaleDragger->getBottomLeftHandlePosition()[0], 0.0,cornerScaleDragger->getBottomLeftHandlePosition()[1]), handleNode, handleScaleFactor); cornerScaleDragger->addChild(handleScene); cornerScaleDragger->setBottomLeftHandleNode(*handleScene); } // Create a bottom right box. { osg::Node* handleScene = createHandleScene(osg::Vec3(cornerScaleDragger->getBottomRightHandlePosition()[0], 0.0,cornerScaleDragger->getBottomRightHandlePosition()[1]), handleNode, handleScaleFactor); cornerScaleDragger->addChild(handleScene); cornerScaleDragger->setBottomRightHandleNode(*handleScene); } // Create a top right box. { osg::Node* handleScene = createHandleScene(osg::Vec3(cornerScaleDragger->getTopRightHandlePosition()[0], 0.0,cornerScaleDragger->getTopRightHandlePosition()[1]), handleNode, handleScaleFactor); cornerScaleDragger->addChild(handleScene); cornerScaleDragger->setTopRightHandleNode(*handleScene); } } void createEdgeScaleDraggerGeometry(Scale1DDragger* horzEdgeScaleDragger, Scale1DDragger* vertEdgeScaleDragger, osg::Node* handleNode, float handleScaleFactor) { // Create a left box. { osg::Node* handleScene = createHandleScene(osg::Vec3(horzEdgeScaleDragger->getLeftHandlePosition(),0.0,0.0), handleNode, handleScaleFactor); horzEdgeScaleDragger->addChild(handleScene); horzEdgeScaleDragger->setLeftHandleNode(*handleScene); } // Create a right box. { osg::Node* handleScene = createHandleScene(osg::Vec3(horzEdgeScaleDragger->getRightHandlePosition(),0.0,0.0), handleNode, handleScaleFactor); horzEdgeScaleDragger->addChild(handleScene); horzEdgeScaleDragger->setRightHandleNode(*handleScene); } // Create a top box. { osg::Node* handleScene = createHandleScene(osg::Vec3(vertEdgeScaleDragger->getLeftHandlePosition(),0.0,0.0), handleNode, handleScaleFactor); vertEdgeScaleDragger->addChild(handleScene); vertEdgeScaleDragger->setLeftHandleNode(*handleScene); } // Create a bottom box. { osg::Node* handleScene = createHandleScene(osg::Vec3(vertEdgeScaleDragger->getRightHandlePosition(),0.0,0.0), handleNode, handleScaleFactor); vertEdgeScaleDragger->addChild(handleScene); vertEdgeScaleDragger->setRightHandleNode(*handleScene); } osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(1.0f, 0.0f, 0.0f)); vertEdgeScaleDragger->setMatrix(osg::Matrix(rotation)); } void createTranslateDraggerGeometry(Scale2DDragger* cornerScaleDragger, TranslatePlaneDragger* translateDragger) { // Create a polygon. { osg::Geode* geode = new osg::Geode; osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(4); (*vertices)[0] = osg::Vec3(cornerScaleDragger->getTopLeftHandlePosition()[0],0.0,cornerScaleDragger->getTopLeftHandlePosition()[1]); (*vertices)[1] = osg::Vec3(cornerScaleDragger->getBottomLeftHandlePosition()[0],0.0,cornerScaleDragger->getBottomLeftHandlePosition()[1]); (*vertices)[2] = osg::Vec3(cornerScaleDragger->getBottomRightHandlePosition()[0],0.0,cornerScaleDragger->getBottomRightHandlePosition()[1]); (*vertices)[3] = osg::Vec3(cornerScaleDragger->getTopRightHandlePosition()[0],0.0,cornerScaleDragger->getTopRightHandlePosition()[1]); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,vertices->size())); osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0,1.0,0.0)); geometry->setNormalArray(normals, osg::Array::BIND_OVERALL); geode->addDrawable(geometry); osg::PolygonMode* polymode = new osg::PolygonMode; polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE); geode->getOrCreateStateSet()->setAttributeAndModes(polymode,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); translateDragger->getTranslate2DDragger()->addChild(geode); } } } TabPlaneDragger::TabPlaneDragger( float handleScaleFactor ) :_handleScaleFactor( handleScaleFactor ) { _cornerScaleDragger = new Scale2DDragger(Scale2DDragger::SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT); addChild(_cornerScaleDragger.get()); addDragger(_cornerScaleDragger.get()); _horzEdgeScaleDragger = new Scale1DDragger(Scale1DDragger::SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT); addChild(_horzEdgeScaleDragger.get()); addDragger(_horzEdgeScaleDragger.get()); _vertEdgeScaleDragger = new Scale1DDragger(Scale1DDragger::SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT); addChild(_vertEdgeScaleDragger.get()); addDragger(_vertEdgeScaleDragger.get()); _translateDragger = new TranslatePlaneDragger(); _translateDragger->setColor(osg::Vec4(0.7f, 0.7f, 0.7f, 1.0f)); addChild(_translateDragger.get()); addDragger(_translateDragger.get()); setParentDragger(getParentDragger()); } TabPlaneDragger::~TabPlaneDragger() { } bool TabPlaneDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { if (ea.getButtonMask() & osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) return false; // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; // Since the translate plane and the handleNode lie on the same plane the hit could've been on either one. But we // need to handle the scaling draggers before the translation. Check if the node path has the scaling nodes else // check for the scaling nodes in next hit. if (_cornerScaleDragger->handle(pointer, ea, aa)) return true; if (_horzEdgeScaleDragger->handle(pointer, ea, aa)) return true; if (_vertEdgeScaleDragger->handle(pointer, ea, aa)) return true; PointerInfo nextPointer(pointer); nextPointer.next(); while (!nextPointer.completed()) { if (_cornerScaleDragger->handle(nextPointer, ea, aa)) return true; if (_horzEdgeScaleDragger->handle(nextPointer, ea, aa)) return true; if (_vertEdgeScaleDragger->handle(nextPointer, ea, aa)) return true; nextPointer.next(); } if (_translateDragger->handle(pointer, ea, aa)) return true; return false; } void TabPlaneDragger::setupDefaultGeometry(bool twoSidedHandle) { osg::ref_ptr handleNode = createHandleNode(_cornerScaleDragger.get(), _handleScaleFactor, twoSidedHandle); createCornerScaleDraggerGeometry(_cornerScaleDragger.get(), handleNode.get(), _handleScaleFactor); createEdgeScaleDraggerGeometry(_horzEdgeScaleDragger.get(),_vertEdgeScaleDragger.get(),handleNode.get(),_handleScaleFactor); createTranslateDraggerGeometry(_cornerScaleDragger.get(), _translateDragger.get()); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/TranslateAxisDragger.cpp0000644000175000017500000001135213151044751027441 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include using namespace osgManipulator; TranslateAxisDragger::TranslateAxisDragger() { _xDragger = new Translate1DDragger(osg::Vec3(0.0,0.0,0.0), osg::Vec3(0.0,0.0,1.0)); addChild(_xDragger.get()); addDragger(_xDragger.get()); _yDragger = new Translate1DDragger(osg::Vec3(0.0,0.0,0.0), osg::Vec3(0.0,0.0,1.0)); addChild(_yDragger.get()); addDragger(_yDragger.get()); _zDragger = new Translate1DDragger(osg::Vec3(0.0,0.0,0.0), osg::Vec3(0.0,0.0,1.0)); addChild(_zDragger.get()); addDragger(_zDragger.get()); _axisLineWidth = 2.0f; _pickCylinderRadius = 0.015f; _coneHeight = 0.1f; setParentDragger(getParentDragger()); } TranslateAxisDragger::~TranslateAxisDragger() { } void TranslateAxisDragger::setupDefaultGeometry() { // Create a line. _lineGeode = new osg::Geode; { osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(2); (*vertices)[0] = osg::Vec3(0.0f,0.0f,0.0f); (*vertices)[1] = osg::Vec3(0.0f,0.0f,1.0f); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2)); _lineGeode->addDrawable(geometry); } // Turn of lighting for line and set line width. { _lineWidth = new osg::LineWidth(); _lineWidth->setWidth(_axisLineWidth); _lineGeode->getOrCreateStateSet()->setAttributeAndModes(_lineWidth.get(), osg::StateAttribute::ON); _lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); } // Add line to all the individual 1D draggers. _xDragger->addChild(_lineGeode.get()); _yDragger->addChild(_lineGeode.get()); _zDragger->addChild(_lineGeode.get()); osg::Geode* geode = new osg::Geode; // Create a cone. { _cone = new osg::Cone (osg::Vec3(0.0f, 0.0f, 1.0f), _coneHeight * 0.25f, _coneHeight); osg::ShapeDrawable* coneDrawable = new osg::ShapeDrawable(_cone.get()); // coneDrawable->setColor(osg::Vec4(0.0f,0.0f,1.0f,1.0f)); geode->addDrawable(coneDrawable); // This ensures correct lighting for scaled draggers. #if !defined(OSG_GLES2_AVAILABLE) geode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); #endif } // Create an invisible cylinder for picking the line. { _cylinder = new osg::Cylinder (osg::Vec3(0.0f,0.0f,0.5f), _pickCylinderRadius, 1.0f); osg::Drawable* geometry = new osg::ShapeDrawable(_cylinder.get()); setDrawableToAlwaysCull(*geometry); geode->addDrawable(geometry); } // Add geode to all 1D draggers. _xDragger->addChild(geode); _yDragger->addChild(geode); _zDragger->addChild(geode); // Rotate X-axis dragger appropriately. { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(1.0f, 0.0f, 0.0f)); _xDragger->setMatrix(osg::Matrix(rotation)); } // Rotate Y-axis dragger appropriately. { osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(0.0f, 1.0f, 0.0f)); _yDragger->setMatrix(osg::Matrix(rotation)); } // Send different colors for each dragger. _xDragger->setColor(osg::Vec4(1.0f,0.0f,0.0f,1.0f)); _yDragger->setColor(osg::Vec4(0.0f,1.0f,0.0f,1.0f)); _zDragger->setColor(osg::Vec4(0.0f,0.0f,1.0f,1.0f)); } void TranslateAxisDragger::setAxisLineWidth(float linePixelWidth) { _axisLineWidth = linePixelWidth; if (_lineWidth.valid()) _lineWidth->setWidth(linePixelWidth); } void TranslateAxisDragger::setPickCylinderRadius(float pickCylinderRadius) { _pickCylinderRadius = pickCylinderRadius; if (_cylinder.valid()) _cylinder->setRadius(pickCylinderRadius); } void TranslateAxisDragger::setConeHeight(float height) { _coneHeight = height; if (_cone.valid()) { _cone->setRadius(0.25f * height); _cone->setHeight(height); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgManipulator/Scale2DDragger.cpp0000644000175000017500000002213413151044751026074 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. #include #include #include #include #include #include using namespace osgManipulator; namespace { osg::Vec2d computeScale(const osg::Vec3d& startProjectedPoint, const osg::Vec3d& projectedPoint, const osg::Vec2d& scaleCenter) { osg::Vec2d scale(1.0,1.0); if ((startProjectedPoint[0] - scaleCenter[0]) != 0.0) scale[0] = (projectedPoint[0] - scaleCenter[0])/(startProjectedPoint[0] - scaleCenter[0]); if ((startProjectedPoint[2] - scaleCenter[1]) != 0.0) scale[1] = (projectedPoint[2] - scaleCenter[1])/(startProjectedPoint[2] - scaleCenter[1]); return scale; } } Scale2DDragger::Scale2DDragger(ScaleMode scaleMode) : Dragger(), _minScale(0.001,0.001), _scaleMode(scaleMode) { _projector = new PlaneProjector(osg::Plane(0.0,1.0,0.0,0.0)); setColor(osg::Vec4(0.0, 1.0, 0.0, 1.0)); setPickColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); _topLeftHandlePosition.set (-0.5,0.5); _bottomLeftHandlePosition.set (-0.5,-0.5); _bottomRightHandlePosition.set(0.5,-0.5); _topRightHandlePosition.set (0.5,0.5); } Scale2DDragger::~Scale2DDragger() { } bool Scale2DDragger::handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { // Check if the dragger node is in the nodepath. if (!pointer.contains(this)) return false; switch (ea.getEventType()) { // Pick start. case (osgGA::GUIEventAdapter::PUSH): { // Get the LocalToWorld matrix for this node and set it for the projector. osg::NodePath nodePathToRoot; computeNodePathToRoot(*this,nodePathToRoot); osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot); _projector->setLocalToWorld(localToWorld); if (_projector->project(pointer, _startProjectedPoint)) { _scaleCenter.set(0.0,0.0); if (pointer.contains(_topLeftHandleNode.get())) { _referencePoint = _topLeftHandlePosition; if (_scaleMode == SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT) _scaleCenter = _bottomRightHandlePosition; } else if (pointer.contains(_bottomLeftHandleNode.get())) { _referencePoint = _bottomLeftHandlePosition; if (_scaleMode == SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT) _scaleCenter = _topRightHandlePosition; } else if (pointer.contains(_bottomRightHandleNode.get())) { _referencePoint = _bottomRightHandlePosition; if (_scaleMode == SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT) _scaleCenter = _topLeftHandlePosition; } else if (pointer.contains(_topRightHandleNode.get())) { _referencePoint = _topRightHandlePosition; if (_scaleMode == SCALE_WITH_OPPOSITE_HANDLE_AS_PIVOT) _scaleCenter = _bottomLeftHandlePosition; } // Generate the motion command. osg::ref_ptr cmd = new Scale2DCommand(); cmd->setStage(MotionCommand::START); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); cmd->setReferencePoint(_referencePoint); // Dispatch command. dispatch(*cmd); // Set color to pick color. setMaterialColor(_pickColor,*this); aa.requestRedraw(); } return true; } // Pick move. case (osgGA::GUIEventAdapter::DRAG): { osg::Vec3d projectedPoint; if (_projector->project(pointer, projectedPoint)) { // Compute scale. osg::Vec2d scale = computeScale(_startProjectedPoint,projectedPoint,_scaleCenter); if (scale[0] < getMinScale()[0]) scale[0] = getMinScale()[0]; if (scale[1] < getMinScale()[1]) scale[1] = getMinScale()[1]; // Generate the motion command. osg::ref_ptr cmd = new Scale2DCommand(); cmd->setStage(MotionCommand::MOVE); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); cmd->setScale(scale); cmd->setScaleCenter(_scaleCenter); cmd->setReferencePoint(_referencePoint); cmd->setMinScale(getMinScale()); // Dispatch command. dispatch(*cmd); aa.requestRedraw(); } return true; } // Pick finish. case (osgGA::GUIEventAdapter::RELEASE): { osg::ref_ptr cmd = new Scale2DCommand(); cmd->setStage(MotionCommand::FINISH); cmd->setReferencePoint(_referencePoint); cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal()); // Dispatch command. dispatch(*cmd); // Reset color. setMaterialColor(_color,*this); aa.requestRedraw(); return true; } default: return false; } } void Scale2DDragger::setupDefaultGeometry() { osg::Geode* lineGeode = new osg::Geode; // Create a line. { osg::Geometry* geometry = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(4); (*vertices)[0].set(_topLeftHandlePosition[0],0.0,_topLeftHandlePosition[1]); (*vertices)[1].set(_bottomLeftHandlePosition[0],0.0,_bottomLeftHandlePosition[1]); (*vertices)[2].set(_bottomRightHandlePosition[0],0.0,_bottomRightHandlePosition[1]); (*vertices)[3].set(_topRightHandlePosition[0],0.0,_topRightHandlePosition[1]); geometry->setVertexArray(vertices); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,vertices->size())); lineGeode->addDrawable(geometry); } // Turn of lighting for line and set line width. lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::LineWidth* linewidth = new osg::LineWidth(); linewidth->setWidth(2.0); lineGeode->getOrCreateStateSet()->setAttributeAndModes(linewidth, osg::StateAttribute::ON); // Add line and cones to the scene. addChild(lineGeode); // Create a top left box. { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(_topLeftHandlePosition[0], 0.0,_topLeftHandlePosition[1]), 0.05))); addChild(geode); setTopLeftHandleNode(*geode); } // Create a bottom left box. { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(_bottomLeftHandlePosition[0], 0.0,_bottomLeftHandlePosition[1]), 0.05))); addChild(geode); setBottomLeftHandleNode(*geode); } // Create a bottom right box. { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(_bottomRightHandlePosition[0], 0.0,_bottomRightHandlePosition[1]), 0.05))); addChild(geode); setBottomRightHandleNode(*geode); } // Create a top right box. { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(_topRightHandlePosition[0], 0.0,_topRightHandlePosition[1]), 0.05))); addChild(geode); setTopRightHandleNode(*geode); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/0000755000175000017500000000000013151044751020647 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Version.cpp0000644000175000017500000000152113151044751022777 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include extern "C" { const char* osgDBGetVersion() { return osgGetVersion(); } const char* osgDBGetLibraryName() { return "OpenSceneGraph DB (Data Base) Library"; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/FileNameUtils.cpp0000644000175000017500000004044113151044751024057 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #ifdef WIN32 #define _WIN32_WINNT 0x0500 #include #endif #if defined(__sgi) #include #elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__) #include using std::tolower; #endif #if defined(__GNU__) && !defined(PATH_MAX) #define PATH_MAX 4096 #endif using namespace std; static const char * const PATH_SEPARATORS = "/\\"; static unsigned int PATH_SEPARATORS_LEN = 2; std::string osgDB::getFilePath(const std::string& fileName) { std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); if (slash==std::string::npos) return std::string(); else return std::string(fileName, 0, slash); } std::string osgDB::getSimpleFileName(const std::string& fileName) { std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); if (slash==std::string::npos) return fileName; else return std::string(fileName.begin()+slash+1,fileName.end()); } std::string osgDB::getFileExtension(const std::string& fileName) { std::string::size_type dot = fileName.find_last_of('.'); std::string::size_type slash = fileName.find_last_of(PATH_SEPARATORS); if (dot==std::string::npos || (slash!=std::string::npos && dotisProtocolRegistered(proto); } std::string osgDB::getServerProtocol(const std::string& filename) { std::string::size_type pos(filename.find("://")); if (pos != std::string::npos) return filename.substr(0,pos); return ""; } std::string osgDB::getServerAddress(const std::string& filename) { std::string::size_type pos(filename.find("://")); if (pos != std::string::npos) { std::string::size_type pos_slash = filename.find_first_of('/',pos+3); if (pos_slash!=std::string::npos) { return filename.substr(pos+3,pos_slash-pos-3); } else { return filename.substr(pos+3,std::string::npos); } } return ""; } std::string osgDB::getServerFileName(const std::string& filename) { std::string::size_type pos(filename.find("://")); if (pos != std::string::npos) { std::string::size_type pos_slash = filename.find_first_of('/',pos+3); if (pos_slash!=std::string::npos) { return filename.substr(pos_slash+1,std::string::npos); } else { return ""; } } return filename; } std::string osgDB::concatPaths(const std::string& left, const std::string& right) { #if defined(WIN32) && !defined(__CYGWIN__) const char delimiterNative = WINDOWS_PATH_SEPARATOR; const char delimiterForeign = UNIX_PATH_SEPARATOR; #else const char delimiterNative = UNIX_PATH_SEPARATOR; const char delimiterForeign = WINDOWS_PATH_SEPARATOR; #endif if(left.empty()) { return(right); } char lastChar = left[left.size() - 1]; if(lastChar == delimiterNative) { return left + right; } else if(lastChar == delimiterForeign) { return left.substr(0, left.size() - 1) + delimiterNative + right; } else // lastChar != a delimiter { return left + delimiterNative + right; } } std::string osgDB::getRealPath(const std::string& path) { #if defined(WIN32) && !defined(__CYGWIN__) #ifdef OSG_USE_UTF8_FILENAME std::wstring wpath = convertUTF8toUTF16(path); wchar_t retbuf[MAX_PATH + 1]; wchar_t tempbuf1[MAX_PATH + 1]; if (GetFullPathNameW(wpath.c_str(), _countof(retbuf), retbuf, NULL)==0) { return path; } // Force drive letter to upper case if ((retbuf[1] == ':') && iswlower(retbuf[0])) retbuf[0] = towupper(retbuf[0]); if (fileExists(convertUTF16toUTF8(retbuf))) { // Canonicalise the full path GetShortPathNameW(retbuf, tempbuf1, _countof(tempbuf1)); GetLongPathNameW(tempbuf1, retbuf, _countof(retbuf)); return convertUTF16toUTF8(retbuf); } else { std::string retbuf8 = convertUTF16toUTF8(retbuf); // Canonicalise the directories std::string FilePath = getFilePath(retbuf8); wchar_t tempbuf2[MAX_PATH + 1]; if (0 == GetShortPathNameW(convertUTF8toUTF16(FilePath).c_str(), tempbuf1, _countof(tempbuf1))) return retbuf8; if (0 == GetLongPathNameW(tempbuf1, tempbuf2, _countof(tempbuf2))) return retbuf8; FilePath = convertUTF16toUTF8(tempbuf2); FilePath += WINDOWS_PATH_SEPARATOR; FilePath.append(getSimpleFileName(retbuf8)); return FilePath; } #else // Not unicode compatible should give an error if UNICODE defined char retbuf[MAX_PATH + 1]; char tempbuf1[MAX_PATH + 1]; GetFullPathName(path.c_str(), sizeof(retbuf), retbuf, NULL); // Force drive letter to upper case if ((retbuf[1] == ':') && islower(retbuf[0])) retbuf[0] = _toupper(retbuf[0]); if (fileExists(std::string(retbuf))) { // Canonicalise the full path GetShortPathName(retbuf, tempbuf1, sizeof(tempbuf1)); GetLongPathName(tempbuf1, retbuf, sizeof(retbuf)); return std::string(retbuf); } else { // Canonicalise the directories std::string FilePath = getFilePath(retbuf); char tempbuf2[MAX_PATH + 1]; if (0 == GetShortPathName(FilePath.c_str(), tempbuf1, sizeof(tempbuf1))) return std::string(retbuf); if (0 == GetLongPathName(tempbuf1, tempbuf2, sizeof(tempbuf2))) return std::string(retbuf); FilePath = std::string(tempbuf2); FilePath += WINDOWS_PATH_SEPARATOR; FilePath.append(getSimpleFileName(std::string(retbuf))); return FilePath; } #endif #else char resolved_path[PATH_MAX]; char* result = realpath(path.c_str(), resolved_path); if (result) return std::string(resolved_path); else return path; #endif } namespace osgDB { /** Helper to iterate over elements of a path (including Windows' root, if any). **/ class PathIterator { public: PathIterator(const std::string & v); bool valid() const { return start!=end; } PathIterator & operator++(); std::string operator*(); protected: std::string::const_iterator end; ///< End of path string std::string::const_iterator start; ///< Points to the first char of an element, or ==end() if no more std::string::const_iterator stop; ///< Points to the separator after 'start', or ==end() /// Iterate until 'it' points to something different from a separator std::string::const_iterator skipSeparators(std::string::const_iterator it); std::string::const_iterator next(std::string::const_iterator it); }; } osgDB::PathIterator::PathIterator(const std::string & v) : end(v.end()), start(v.begin()), stop(v.begin()) { operator++(); } osgDB::PathIterator & osgDB::PathIterator::operator++() { if (!valid()) return *this; start = skipSeparators(stop); if (start != end) stop = next(start); return *this; } std::string osgDB::PathIterator::operator*() { if (!valid()) return std::string(); return std::string(start, stop); } std::string::const_iterator osgDB::PathIterator::skipSeparators(std::string::const_iterator it) { for (; it!=end && std::find_first_of(it, it+1, PATH_SEPARATORS, PATH_SEPARATORS+PATH_SEPARATORS_LEN) != it+1; ++it) {} return it; } std::string::const_iterator osgDB::PathIterator::next(std::string::const_iterator it) { return std::find_first_of(it, end, PATH_SEPARATORS, PATH_SEPARATORS+PATH_SEPARATORS_LEN); } void osgDB::getPathElements(const std::string& path, std::vector & out_elements) { out_elements.clear(); for(osgDB::PathIterator it(path); it.valid(); ++it) out_elements.push_back(*it); } std::string osgDB::getPathRoot(const std::string& path) { // Test for unix root if (path.empty()) return ""; if (path[0] == '/') return "/"; // Now test for Windows root if (path.length()<2) return ""; if (path[1] == ':') return path.substr(0, 2); // We should check that path[0] is a letter, but as ':' is invalid in paths in other cases, that's not a problem. return ""; } bool osgDB::isAbsolutePath(const std::string& path) { // Test for unix root if (path.empty()) return false; if (path[0] == '/') return true; // Now test for Windows root if (path.length()<2) return false; if (path[0] == '\\' && path[1] == '\\') return true; return path[1] == ':'; // We should check that path[0] is a letter, but as ':' is invalid in paths in other cases, that's not a problem. } std::string osgDB::getPathRelative(const std::string& from, const std::string& to) { // This implementation is not 100% robust, and should be replaced with C++0x "std::path" as soon as possible. // Definition: an "element" is a part between slashes. Ex: "/a/b" has two elements ("a" and "b"). // Algorithm: // 1. If paths are neither both absolute nor both relative, then we cannot do anything (we need to make them absolute, but need additionnal info on how to make it). Return. // 2. If both paths are absolute and root isn't the same (for Windows only, as roots are of the type "C:", "D:"), then the operation is impossible. Return. // 3. Iterate over two paths elements until elements are equal // 4. For each remaining element in "from", add ".." to result // 5. For each remaining element in "to", add this element to result // 1 & 2 const std::string root = getPathRoot(from); if (root != getPathRoot(to)) { OSG_INFO << "Cannot relativise paths. From=" << from << ", To=" << to << ". Returning 'to' unchanged." << std::endl; //return to; return osgDB::getSimpleFileName(to); } // 3 PathIterator itFrom(from), itTo(to); // Iterators may point to Windows roots. As we tested they are equal, there is no need to ++itFrom and ++itTo. // However, if we got an Unix root, we must add it to the result. std::string res(root == "/" ? "/" : ""); for(; itFrom.valid() && itTo.valid() && *itFrom==*itTo; ++itFrom, ++itTo) {} // 4 for(; itFrom.valid(); ++itFrom) res += "../"; // 5 for(; itTo.valid(); ++itTo) res += *itTo + "/"; // Remove trailing slash before returning if (!res.empty() && std::find_first_of(res.rbegin(), res.rbegin()+1, PATH_SEPARATORS, PATH_SEPARATORS+PATH_SEPARATORS_LEN) != res.rbegin()+1) { return res.substr(0, res.length()-1); } return res; } //using namespace osgDB; //std::string testA = getPathRelative("C:\\a\\b", "C:\\a/b/d/f"); // d/f //std::string testB = getPathRelative("C:\\a\\d", "C:\\a/b/d/f"); // ../b/d/f //std::string testC = getPathRelative("C:\\ab", "C:\\a/b/d/f"); // ../a/b/d/f //std::string testD = getPathRelative("a/d", "a/d"); // "" //std::string testE = getPathRelative("a", "a/d"); // ../d //std::string testF = getPathRelative("C:/a/b", "a/d"); // Precondition fail. Returns d. //std::string testG = getPathRelative("/a/b", "a/d"); // Precondition fail. Returns d. //std::string testH = getPathRelative("a/b", "/a/d"); // Precondition fail. Returns d. OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/PluginQuery.cpp0000644000175000017500000001427613151044751023651 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial applications, * as long as this copyright notice is maintained. * * This application 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. */ #include #include #include #include using namespace osgDB; FileNameList osgDB::listAllAvailablePlugins() { FileNameList pluginFiles; std::string validExtension = ADDQUOTES(OSG_PLUGIN_EXTENSION); std::string pluginDirectoryName = std::string("osgPlugins-")+std::string(osgGetVersion()); std::string fullPath = osgDB::findLibraryFile(pluginDirectoryName); if (!fullPath.empty()) { osgDB::DirectoryContents contents = getDirectoryContents(fullPath); for(DirectoryContents::iterator itr = contents.begin(); itr != contents.end(); ++itr) { std::string::size_type pos = itr->find("osgdb_"); if (pos==std::string::npos) { continue; } std::string ext = getFileExtensionIncludingDot(*itr); if (ext != validExtension) { continue; } pluginFiles.push_back(fullPath + std::string("/")+*itr); } } return pluginFiles; } bool osgDB::queryPlugin(const std::string& fileName, ReaderWriterInfoList& infoList) { typedef std::set ReaderWriterSet; ReaderWriterSet previouslyLoadedReaderWriters; const Registry::ReaderWriterList& rwList = osgDB::Registry::instance()->getReaderWriterList(); for(Registry::ReaderWriterList::const_iterator itr = rwList.begin(); itr != rwList.end(); ++itr) { const ReaderWriter* rw = itr->get(); previouslyLoadedReaderWriters.insert(rw); } if (osgDB::Registry::instance()->loadLibrary(fileName)) { const Registry::ReaderWriterList& rwList = osgDB::Registry::instance()->getReaderWriterList(); for(Registry::ReaderWriterList::const_iterator itr = rwList.begin(); itr != rwList.end(); ++itr) { const ReaderWriter* rw = itr->get(); if (previouslyLoadedReaderWriters.count(rw)==0) { osg::ref_ptr rwi = new ReaderWriterInfo; rwi->plugin = fileName; rwi->description = rw->className(); rwi->protocols = rw->supportedProtocols(); rwi->extensions = rw->supportedExtensions(); rwi->options = rw->supportedOptions(); rwi->features = rw->supportedFeatures(); infoList.push_back(rwi.get()); } } osgDB::Registry::instance()->closeLibrary(fileName); return true; } else { return false; } } static std::string padwithspaces(const std::string& str, unsigned int padLength) { std::string newStr(str); while(newStr.length()first.length()>longestOptionLength) longestOptionLength = fdm_itr->first.length(); } for(fdm_itr = info.extensions.begin(); fdm_itr != info.extensions.end(); ++fdm_itr) { if (fdm_itr->first.length()>longestOptionLength) longestOptionLength = fdm_itr->first.length(); } for(fdm_itr = info.options.begin(); fdm_itr != info.options.end(); ++fdm_itr) { if (fdm_itr->first.length()>longestOptionLength) longestOptionLength = fdm_itr->first.length(); } unsigned int padLength = longestOptionLength+4; for(fdm_itr = info.protocols.begin(); fdm_itr != info.protocols.end(); ++fdm_itr) { out<<" protocol : "<first, padLength)<second<first, padLength-1)<second<first, padLength)<second< #include #include #include #include using namespace osgDB; osg::Object* ReaderWriter::ReadResult::getObject() { return _object.get(); } osg::Image* ReaderWriter::ReadResult::getImage() { return dynamic_cast(_object.get()); } osg::HeightField* ReaderWriter::ReadResult::getHeightField() { return dynamic_cast(_object.get()); } osg::Node* ReaderWriter::ReadResult::getNode() { return dynamic_cast(_object.get()); } osgDB::Archive* ReaderWriter::ReadResult::getArchive() { return dynamic_cast(_object.get()); } osg::Shader* ReaderWriter::ReadResult::getShader() { return dynamic_cast(_object.get()); } osg::Script* ReaderWriter::ReadResult::getScript() { return dynamic_cast(_object.get()); } osg::Object* ReaderWriter::ReadResult::takeObject() { osg::Object* obj = _object.get(); if (obj) { obj->ref(); _object=NULL; obj->unref_nodelete(); } return obj; } osg::Image* ReaderWriter::ReadResult::takeImage() { osg::Image* image=dynamic_cast(_object.get()); if (image) { image->ref(); _object=NULL; image->unref_nodelete(); } return image; } osg::HeightField* ReaderWriter::ReadResult::takeHeightField() { osg::HeightField* hf=dynamic_cast(_object.get()); if (hf) { hf->ref(); _object=NULL; hf->unref_nodelete(); } return hf; } osg::Node* ReaderWriter::ReadResult::takeNode() { osg::Node* node=dynamic_cast(_object.get()); if (node) { node->ref(); _object=NULL; node->unref_nodelete(); } return node; } osgDB::Archive* ReaderWriter::ReadResult::takeArchive() { osgDB::Archive* archive=dynamic_cast(_object.get()); if (archive) { archive->ref(); _object=NULL; archive->unref_nodelete(); } return archive; } osg::Shader* ReaderWriter::ReadResult::takeShader() { osg::Shader* shader=dynamic_cast(_object.get()); if (shader) { shader->ref(); _object=NULL; shader->unref_nodelete(); } return shader; } osg::Script* ReaderWriter::ReadResult::takeScript() { osg::Script* script=dynamic_cast(_object.get()); if (script) { script->ref(); _object=NULL; script->unref_nodelete(); } return script; } ReaderWriter::~ReaderWriter() { } bool ReaderWriter::acceptsExtension(const std::string& extension) const { // check for an exact match std::string lowercase_ext = convertToLowerCase(extension); return (_supportedExtensions.count(lowercase_ext)!=0); } bool ReaderWriter::acceptsProtocol(const std::string& protocol) const { std::string lowercase_protocol = convertToLowerCase(protocol); return (_supportedProtocols.count(lowercase_protocol)!=0); } void ReaderWriter::supportsProtocol(const std::string& fmt, const std::string& description) { Registry::instance()->registerProtocol(fmt); _supportedProtocols[convertToLowerCase(fmt)] = description; } void ReaderWriter::supportsExtension(const std::string& fmt, const std::string& description) { _supportedExtensions[convertToLowerCase(fmt)] = description; } void ReaderWriter::supportsOption(const std::string& fmt, const std::string& description) { _supportedOptions[fmt] = description; } ReaderWriter::Features ReaderWriter::supportedFeatures() const { int features = FEATURE_NONE; std::string dummyFilename; if (readObject(dummyFilename,0).status()!=ReadResult::NOT_IMPLEMENTED) features |= FEATURE_READ_OBJECT; if (readImage(dummyFilename,0).status()!=ReadResult::NOT_IMPLEMENTED) features |= FEATURE_READ_IMAGE; if (readHeightField(dummyFilename,0).status()!=ReadResult::NOT_IMPLEMENTED) features |= FEATURE_READ_HEIGHT_FIELD; if (readShader(dummyFilename,0).status()!=ReadResult::NOT_IMPLEMENTED) features |= FEATURE_READ_SHADER; if (readNode(dummyFilename,0).status()!=ReadResult::NOT_IMPLEMENTED) features |= FEATURE_READ_NODE; osg::ref_ptr image = new osg::Image; osg::ref_ptr hf = new osg::HeightField; osg::ref_ptr shader = new osg::Shader; osg::ref_ptr node = new osg::Node; if (writeObject(*image, dummyFilename,0).status()!=WriteResult::NOT_IMPLEMENTED) features |= FEATURE_WRITE_OBJECT; if (writeImage(*image,dummyFilename,0).status()!=WriteResult::NOT_IMPLEMENTED) features |= FEATURE_WRITE_IMAGE; if (writeHeightField(*hf,dummyFilename,0).status()!=WriteResult::NOT_IMPLEMENTED) features |= FEATURE_WRITE_HEIGHT_FIELD; if (writeShader(*shader,dummyFilename,0).status()!=WriteResult::NOT_IMPLEMENTED) features |= FEATURE_WRITE_SHADER; if (writeNode(*node, dummyFilename,0).status()!=WriteResult::NOT_IMPLEMENTED) features |= FEATURE_WRITE_NODE; return Features(features); } ReaderWriter::FeatureList ReaderWriter::featureAsString(ReaderWriter::Features feature) { typedef struct { ReaderWriter::Features feature; const char *s; } FeatureStringList; FeatureStringList list[] = { { FEATURE_READ_OBJECT, "readObject" }, { FEATURE_READ_IMAGE, "readImage" }, { FEATURE_READ_HEIGHT_FIELD, "readHeightField" }, { FEATURE_READ_NODE, "readNode" }, { FEATURE_READ_SHADER, "readShader" }, { FEATURE_WRITE_OBJECT, "writeObject" }, { FEATURE_WRITE_IMAGE, "writeImage" }, { FEATURE_WRITE_HEIGHT_FIELD, "writeHeightField" }, { FEATURE_WRITE_NODE, "writeNode" }, { FEATURE_WRITE_SHADER, "writeShader" }, { FEATURE_NONE,0 } }; FeatureList result; for(FeatureStringList *p=list; p->feature != 0; p++) { if ((feature & p->feature) != 0) result.push_back(p->s); } return result; } bool ReaderWriter::fileExists(const std::string& filename, const Options* /*options*/) const { return ::osgDB::fileExists(filename); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/DynamicLibrary.cpp0000644000175000017500000001341413151044751024267 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //The dlopen calls were not adding to OS X until 10.3 #ifdef __APPLE__ #include #if !defined(MAC_OS_X_VERSION_10_3) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3) #define APPLE_PRE_10_3 #endif #endif #if defined(WIN32) && !defined(__CYGWIN__) #include #include #include #elif defined(__APPLE__) && defined(APPLE_PRE_10_3) #include #else // all other unix #include #ifdef __hpux // Although HP-UX has dlopen() it is broken! We therefore need to stick // to shl_load()/shl_unload()/shl_findsym() #include #include #else #include #endif #endif #include #include #include #include #include #include using namespace osgDB; DynamicLibrary::DynamicLibrary(const std::string& name, HANDLE handle) { _name = name; _handle = handle; OSG_INFO<<"Opened DynamicLibrary "<<_name<(_handle), FALSE); #elif defined(__hpux) // fortunately, shl_t is a pointer shl_unload (static_cast(_handle)); #else // other unix dlclose(_handle); #endif } } DynamicLibrary* DynamicLibrary::loadLibrary(const std::string& libraryName) { HANDLE handle = NULL; std::string fullLibraryName = osgDB::findLibraryFile(libraryName); if (!fullLibraryName.empty()) handle = getLibraryHandle( fullLibraryName ); // try the lib we have found else handle = getLibraryHandle( libraryName ); // havn't found a lib ourselves, see if the OS can find it simply from the library name. if (handle) return new DynamicLibrary(libraryName,handle); // else no lib found so report errors. OSG_INFO << "DynamicLibrary::failed loading \""<( GetProcAddress( (HMODULE)_handle, procName.c_str() ) ); #elif defined(__APPLE__) && defined(APPLE_PRE_10_3) std::string temp("_"); NSSymbol symbol; temp += procName; // Mac OS X prepends an underscore on function names symbol = NSLookupSymbolInModule(static_cast(_handle), temp.c_str()); return NSAddressOfSymbol(symbol); #elif defined(__hpux) void* result = NULL; if (shl_findsym (reinterpret_cast(&_handle), procName.c_str(), TYPE_PROCEDURE, result) == 0) { return result; } else { OSG_WARN << "DynamicLibrary::failed looking up " << procName << std::endl; OSG_WARN << "DynamicLibrary::error " << strerror(errno) << std::endl; return NULL; } #else // other unix void* sym = dlsym( _handle, procName.c_str() ); if (!sym) { OSG_WARN << "DynamicLibrary::failed looking up " << procName << std::endl; OSG_WARN << "DynamicLibrary::error " << dlerror() << std::endl; } return sym; #endif } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/ConvertBase64.cpp0000644000175000017500000002503513151044751023745 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ /* This file is derived from the libb64 project which itself was released to public domain. * For details, see http://sourceforge.net/projects/libb64. Original code by Chris Venter * c++ wrapper for a base64 encoding and decoding algorithm */ #include #include #include namespace osgDB { const int CHARS_PER_LINE = 72; int base64_decode_value(char value_in) { static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; static const char decoding_size = sizeof(decoding); value_in -= 43; if (value_in < 0 || value_in > decoding_size) return -1; return decoding[(int)value_in]; } void base64_init_decodestate(base64_decodestate* state_in) { state_in->step = step_a; state_in->plainchar = 0; } int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) { const char* codechar = code_in; char* plainchar = plaintext_out; char fragment; *plainchar = state_in->plainchar; switch (state_in->step) { while (1) { case step_a: do { if (codechar == code_in+length_in) { state_in->step = step_a; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar = (fragment & 0x03f) << 2; case step_b: do { if (codechar == code_in+length_in) { state_in->step = step_b; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar++ |= (fragment & 0x030) >> 4; *plainchar = (fragment & 0x00f) << 4; case step_c: do { if (codechar == code_in+length_in) { state_in->step = step_c; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar++ |= (fragment & 0x03c) >> 2; *plainchar = (fragment & 0x003) << 6; case step_d: do { if (codechar == code_in+length_in) { state_in->step = step_d; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar++ |= (fragment & 0x03f); } } /* control should not reach here */ return plainchar - plaintext_out; } void base64_init_encodestate(base64_encodestate* state_in) { state_in->step = step_A; state_in->result = 0; state_in->stepcount = 0; } char base64_encode_value(char value_in) { static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; if (value_in > 63) return '='; return encoding[(int)value_in]; } int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) { const char* plainchar = plaintext_in; const char* const plaintextend = plaintext_in + length_in; char* codechar = code_out; char result; char fragment; result = state_in->result; switch (state_in->step) { while (1) { case step_A: if (plainchar == plaintextend) { state_in->result = result; state_in->step = step_A; return codechar - code_out; } fragment = *plainchar++; result = (fragment & 0x0fc) >> 2; *codechar++ = base64_encode_value(result); result = (fragment & 0x003) << 4; case step_B: if (plainchar == plaintextend) { state_in->result = result; state_in->step = step_B; return codechar - code_out; } fragment = *plainchar++; result |= (fragment & 0x0f0) >> 4; *codechar++ = base64_encode_value(result); result = (fragment & 0x00f) << 2; case step_C: if (plainchar == plaintextend) { state_in->result = result; state_in->step = step_C; return codechar - code_out; } fragment = *plainchar++; result |= (fragment & 0x0c0) >> 6; *codechar++ = base64_encode_value(result); result = (fragment & 0x03f) >> 0; *codechar++ = base64_encode_value(result); ++(state_in->stepcount); if (state_in->stepcount == CHARS_PER_LINE/4) { *codechar++ = '\n'; state_in->stepcount = 0; } } } /* control should not reach here */ return codechar - code_out; } int base64_encode_blockend(char* code_out, base64_encodestate* state_in) { char* codechar = code_out; switch (state_in->step) { case step_B: *codechar++ = base64_encode_value(state_in->result); *codechar++ = '='; *codechar++ = '='; break; case step_C: *codechar++ = base64_encode_value(state_in->result); *codechar++ = '='; break; case step_A: break; } *codechar++ = '\n'; return codechar - code_out; } int Base64encoder::encode(char value_in) { return base64_encode_value(value_in); } int Base64encoder::encode(const char* code_in, const int length_in, char* plaintext_out) { return base64_encode_block(code_in, length_in, plaintext_out, &_state); } int Base64encoder::encode_end(char* plaintext_out) { return base64_encode_blockend(plaintext_out, &_state); } void Base64encoder::encode(std::istream& istream_in, std::ostream& ostream_in) { base64_init_encodestate(&_state); const int N = _buffersize; char* plaintext = new char[N]; char* code = new char[2*N]; int plainlength; int codelength; do { istream_in.read(plaintext, N); plainlength = istream_in.gcount(); codelength = encode(plaintext, plainlength, code); ostream_in.write(code, codelength); } while (istream_in.good() && plainlength > 0); codelength = encode_end(code); ostream_in.write(code, codelength); base64_init_encodestate(&_state); delete [] code; delete [] plaintext; } void Base64encoder::encode(const char* chars_in, int length_in, std::string& code_out) { std::stringstream stream_out; { std::stringstream stream_in; { stream_in< 0); base64_init_decodestate(&_state); delete [] code; delete [] plaintext; } char* Base64decoder::decode(const std::vector& str_in, std::vector& pos_out) { std::stringstream stream_out; { std::stringstream stream_in; pos_out.resize(str_in.size()); for (unsigned int i = 0; i < str_in.size(); ++i) { stream_in.clear(); stream_in< #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif using namespace osgDB; using namespace OpenThreads; static osg::ApplicationUsageProxy DatabasePager_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DO_PRE_COMPILE ","Switch on or off the pre compile of OpenGL object database pager."); static osg::ApplicationUsageProxy DatabasePager_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_DRAWABLE ","Set the drawable policy for setting of loaded drawable to specified type. mode can be one of DoNotModify, DisplayList, VBO or VertexArrays>."); static osg::ApplicationUsageProxy DatabasePager_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_PRIORITY ", "Set the thread priority to DEFAULT, MIN, LOW, NOMINAL, HIGH or MAX."); static osg::ApplicationUsageProxy DatabasePager_e11(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAX_PAGEDLOD ","Set the target maximum number of PagedLOD to maintain."); static osg::ApplicationUsageProxy DatabasePager_e12(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_ASSIGN_PBO_TO_IMAGES ","Set whether PixelBufferObjects should be assigned to Images to aid download to the GPU."); // Convert function objects that take pointer args into functions that a // reference to an osg::ref_ptr. This is quite useful for doing STL // operations on lists of ref_ptr. This code assumes that a function // with an argument const Foo* should be composed into a function of // argument type ref_ptr&, not ref_ptr&. Some support // for that should be added to make this more general. namespace { template struct PointerTraits { typedef class NullType {} PointeeType; }; template struct PointerTraits { typedef U PointeeType; }; template struct PointerTraits { typedef U PointeeType; }; template class RefPtrAdapter : public std::unary_function::PointeeType>, typename FuncObj::result_type> { public: typedef typename PointerTraits::PointeeType PointeeType; typedef osg::ref_ptr RefPtrType; explicit RefPtrAdapter(const FuncObj& funcObj) : _func(funcObj) {} typename FuncObj::result_type operator()(const RefPtrType& refPtr) const { return _func(refPtr.get()); } protected: FuncObj _func; }; template RefPtrAdapter refPtrAdapt(const FuncObj& func) { return RefPtrAdapter(func); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // CountPagedLODList // struct DatabasePager::DatabasePagerCompileCompletedCallback : public osgUtil::IncrementalCompileOperation::CompileCompletedCallback { DatabasePagerCompileCompletedCallback(osgDB::DatabasePager* pager, osgDB::DatabasePager::DatabaseRequest* databaseRequest): _pager(pager), _databaseRequest(databaseRequest) {} virtual bool compileCompleted(osgUtil::IncrementalCompileOperation::CompileSet* /*compileSet*/) { _pager->compileCompleted(_databaseRequest.get()); return true; } osgDB::DatabasePager* _pager; osg::ref_ptr _databaseRequest; }; void DatabasePager::compileCompleted(DatabaseRequest* databaseRequest) { //OSG_NOTICE<<"DatabasePager::compileCompleted("<remove(databaseRequest); _dataToMergeList->add(databaseRequest); } // This class is a helper for the management of SetBasedPagedLODList. class DatabasePager::ExpirePagedLODsVisitor : public osg::NodeVisitor { public: ExpirePagedLODsVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { } META_NodeVisitor("osgDB","ExpirePagedLODsVisitor") virtual void apply(osg::PagedLOD& plod) { _childPagedLODs.insert(&plod); markRequestsExpired(&plod); traverse(plod); } // Remove expired children from a PagedLOD. On return // removedChildren contains the nodes removed by the call to // PagedLOD::removeExpiredChildren, and the _childPagedLODs member // contains all the PagedLOD objects found in those children's // subgraphs. bool removeExpiredChildrenAndFindPagedLODs(osg::PagedLOD* plod, double expiryTime, unsigned int expiryFrame, osg::NodeList& removedChildren) { size_t sizeBefore = removedChildren.size(); plod->removeExpiredChildren(expiryTime, expiryFrame, removedChildren); for(size_t i = sizeBefore; iaccept(*this); } return sizeBefore!=removedChildren.size(); } typedef std::set > PagedLODset; PagedLODset _childPagedLODs; private: void markRequestsExpired(osg::PagedLOD* plod) { unsigned numFiles = plod->getNumFileNames(); for (unsigned i = 0; i < numFiles; ++i) { DatabasePager::DatabaseRequest* request = dynamic_cast(plod->getDatabaseRequest(i).get()); if (request) request->_groupExpired = true; } } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SetBasedPagedLODList // class SetBasedPagedLODList : public DatabasePager::PagedLODList { public: typedef std::set< osg::observer_ptr > PagedLODs; PagedLODs _pagedLODs; virtual PagedLODList* clone() { return new SetBasedPagedLODList(); } virtual void clear() { _pagedLODs.clear(); } virtual unsigned int size() { return _pagedLODs.size(); } virtual void removeExpiredChildren( int numberChildrenToRemove, double expiryTime, unsigned int expiryFrame, DatabasePager::ObjectList& childrenRemoved, bool visitActive) { int leftToRemove = numberChildrenToRemove; for(PagedLODs::iterator itr = _pagedLODs.begin(); itr!=_pagedLODs.end() && leftToRemove > 0; ) { osg::ref_ptr plod; if (itr->lock(plod)) { bool plodActive = expiryFrame < plod->getFrameNumberOfLastTraversal(); if (visitActive==plodActive) // true if (visitActive && plodActive) OR (!visitActive &&!plodActive) { DatabasePager::ExpirePagedLODsVisitor expirePagedLODsVisitor; osg::NodeList expiredChildren; // expired PagedLODs expirePagedLODsVisitor.removeExpiredChildrenAndFindPagedLODs( plod.get(), expiryTime, expiryFrame, expiredChildren); // Clear any expired PagedLODs out of the set for (DatabasePager::ExpirePagedLODsVisitor::PagedLODset::iterator citr = expirePagedLODsVisitor._childPagedLODs.begin(), end = expirePagedLODsVisitor._childPagedLODs.end(); citr != end; ++citr) { osg::observer_ptr clod(*citr); // This child PagedLOD cannot be equal to the // PagedLOD pointed to by itr because it must be // in itr's subgraph. Therefore erasing it doesn't // invalidate itr. if (_pagedLODs.erase(clod) > 0) leftToRemove--; } std::copy(expiredChildren.begin(), expiredChildren.end(), std::back_inserter(childrenRemoved)); } // advance the iterator to the next element ++itr; } else { _pagedLODs.erase(itr++); // numberChildrenToRemove includes possibly expired // observer pointers. leftToRemove--; OSG_INFO<<"DatabasePager::removeExpiredSubgraphs() _inactivePagedLOD has been invalidated, but ignored"<(itr->get()); osg::observer_ptr obs_ptr(plod); PagedLODs::iterator plod_itr = _pagedLODs.find(obs_ptr); if (plod_itr != _pagedLODs.end()) { OSG_INFO<<"Removing node from PagedLOD list"<& plod) { if (_pagedLODs.count(plod)!=0) { OSG_NOTICE<<"Warning: SetBasedPagedLODList::insertPagedLOD("<& plod) const { return (_pagedLODs.count(plod)!=0); } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // FindCompileableGLObjectsVisitor // class DatabasePager::FindCompileableGLObjectsVisitor : public osgUtil::StateToCompile { public: FindCompileableGLObjectsVisitor(const DatabasePager* pager, osg::Object* markerObject): osgUtil::StateToCompile(osgUtil::GLObjectsVisitor::COMPILE_DISPLAY_LISTS|osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES, markerObject), _pager(pager), _changeAutoUnRef(false), _valueAutoUnRef(false), _changeAnisotropy(false), _valueAnisotropy(1.0) { _assignPBOToImages = _pager->_assignPBOToImages; _changeAutoUnRef = _pager->_changeAutoUnRef; _valueAutoUnRef = _pager->_valueAutoUnRef; _changeAnisotropy = _pager->_changeAnisotropy; _valueAnisotropy = _pager->_valueAnisotropy; switch(_pager->_drawablePolicy) { case DatabasePager::DO_NOT_MODIFY_DRAWABLE_SETTINGS: // do nothing, leave settings as they came in from loaded database. // OSG_NOTICE<<"DO_NOT_MODIFY_DRAWABLE_SETTINGS"<getBuildKdTreesHint()==osgDB::Options::BUILD_KDTREES && osgDB::Registry::instance()->getKdTreeBuilder()) { _kdTreeBuilder = osgDB::Registry::instance()->getKdTreeBuilder()->clone(); } } META_NodeVisitor("osgDB","FindCompileableGLObjectsVisitor") bool requiresCompilation() const { return !empty(); } virtual void apply(osg::Drawable& drawable) { if (_kdTreeBuilder.valid() && _markerObject.get()!=drawable.getUserData()) { drawable.accept(*_kdTreeBuilder); } StateToCompile::apply(drawable); if (drawable.getUserData()==0) { drawable.setUserData(_markerObject.get()); } } void apply(osg::Texture& texture) { // apply any changes if the texture is not static. if (texture.getDataVariance()!=osg::Object::STATIC && _markerObject.get()!=texture.getUserData()) { if (_changeAutoUnRef) { texture.setUnRefImageDataAfterApply(_valueAutoUnRef); } if ((_changeAnisotropy && texture.getMaxAnisotropy() != _valueAnisotropy)) { texture.setMaxAnisotropy(_valueAnisotropy); } } StateToCompile::apply(texture); if (texture.getUserData()==0) { texture.setUserData(_markerObject.get()); } } const DatabasePager* _pager; bool _changeAutoUnRef; bool _valueAutoUnRef; bool _changeAnisotropy; float _valueAnisotropy; osg::ref_ptr _kdTreeBuilder; protected: FindCompileableGLObjectsVisitor& operator = (const FindCompileableGLObjectsVisitor&) { return *this; } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SortFileRequestFunctor // struct DatabasePager::SortFileRequestFunctor { bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) const { if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true; else if (lhs->_timestampLastRequest_timestampLastRequest) return false; else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest); } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // DatabaseRequest // void DatabasePager::DatabaseRequest::invalidate() { OSG_INFO<<" DatabasePager::DatabaseRequest::invalidate()."<get()); } } void DatabasePager::RequestQueue::invalidate(DatabaseRequest* dr) { // OSG_NOTICE<<"DatabasePager::RequestQueue::invalidate(DatabaseRequest* dr) dr->_compileSet="<_compileSet.get()< compileSet; if (dr->_compileSet.lock(compileSet) && _pager->getIncrementalCompileOperation()) { _pager->getIncrementalCompileOperation()->remove(compileSet.get()); } dr->invalidate(); } bool DatabasePager::RequestQueue::pruneOldRequestsAndCheckIfEmpty() { OpenThreads::ScopedLock lock(_requestMutex); unsigned int frameNumber = _pager->_frameNumber; if (_frameNumberLastPruned != frameNumber) { for(RequestQueue::RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ) { OpenThreads::ScopedLock drLock(_pager->_dr_mutex); if ((*citr)->isRequestCurrent(frameNumber)) { ++citr; } else { invalidate(citr->get()); OSG_INFO<<"DatabasePager::RequestQueue::pruneOldRequestsAndCheckIfEmpty(): Pruning "<<(*citr)< lock(_requestMutex); return _requestList.empty(); } unsigned int DatabasePager::RequestQueue::size() { OpenThreads::ScopedLock lock(_requestMutex); return _requestList.size(); } void DatabasePager::RequestQueue::clear() { OpenThreads::ScopedLock lock(_requestMutex); for(RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ++citr) { OpenThreads::ScopedLock drLock(_pager->_dr_mutex); invalidate(citr->get()); } _requestList.clear(); _frameNumberLastPruned = _pager->_frameNumber; updateBlock(); } void DatabasePager::RequestQueue::add(DatabasePager::DatabaseRequest* databaseRequest) { OpenThreads::ScopedLock lock(_requestMutex); addNoLock(databaseRequest); } void DatabasePager::RequestQueue::remove(DatabasePager::DatabaseRequest* databaseRequest) { // OSG_NOTICE<<"DatabasePager::RequestQueue::remove(DatabaseRequest* databaseRequest)"< lock(_requestMutex); for(RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ++citr) { if (citr->get()==databaseRequest) { // OSG_NOTICE<<" done remove(DatabaseRequest* databaseRequest)"< lock(_requestMutex); _requestList.swap(requestList); } void DatabasePager::RequestQueue::takeFirst(osg::ref_ptr& databaseRequest) { OpenThreads::ScopedLock lock(_requestMutex); if (!_requestList.empty()) { DatabasePager::SortFileRequestFunctor highPriority; RequestQueue::RequestList::iterator selected_itr = _requestList.end(); int frameNumber = _pager->_frameNumber; for(RequestQueue::RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ) { OpenThreads::ScopedLock drLock(_pager->_dr_mutex); if ((*citr)->isRequestCurrent(frameNumber)) { if (selected_itr==_requestList.end() || highPriority(*citr, *selected_itr)) { selected_itr = citr; } ++citr; } else { invalidate(citr->get()); OSG_INFO<<"DatabasePager::RequestQueue::takeFirst(): Pruning "<<(*citr)< read_queue; osg::ref_ptr out_queue; switch(_mode) { case(HANDLE_ALL_REQUESTS): read_queue = _pager->_fileRequestQueue; break; case(HANDLE_NON_HTTP): read_queue = _pager->_fileRequestQueue; out_queue = _pager->_httpRequestQueue; break; case(HANDLE_ONLY_HTTP): read_queue = _pager->_httpRequestQueue; break; } do { _active = false; read_queue->block(); if (_done) { break; } _active = true; OSG_INFO<<_name<<": _pager->size()= "<size()<<" to delete = "<_childrenToDeleteList.size()<_deleteRemovedSubgraphsInDatabaseThread/* && !(read_queue->_childrenToDeleteList.empty())*/) { ObjectList deleteList; { // Don't hold lock during destruction of deleteList OpenThreads::ScopedLock lock(read_queue->_requestMutex); if (!read_queue->_childrenToDeleteList.empty()) { deleteList.swap(read_queue->_childrenToDeleteList); read_queue->updateBlock(); } } } // // load any subgraphs that are required. // osg::ref_ptr databaseRequest; read_queue->takeFirst(databaseRequest); bool readFromFileCache = false; osg::ref_ptr fileCache = osgDB::Registry::instance()->getFileCache(); osg::ref_ptr fileLocationCallback = osgDB::Registry::instance()->getFileLocationCallback(); osg::ref_ptr dr_loadOptions; std::string fileName; int frameNumberLastRequest = 0; bool cacheNodes = false; if (databaseRequest.valid()) { { OpenThreads::ScopedLock drLock(_pager->_dr_mutex); dr_loadOptions = databaseRequest->_loadOptions.valid() ? databaseRequest->_loadOptions->cloneOptions() : new osgDB::Options; dr_loadOptions->setTerrain(databaseRequest->_terrain); dr_loadOptions->setParentGroup(databaseRequest->_group); fileName = databaseRequest->_fileName; frameNumberLastRequest = databaseRequest->_frameNumberLastRequest; } if (dr_loadOptions->getFileCache()) fileCache = dr_loadOptions->getFileCache(); if (dr_loadOptions->getFileLocationCallback()) fileLocationCallback = dr_loadOptions->getFileLocationCallback(); // disable the FileCache if the fileLocationCallback tells us that it isn't required for this request. if (fileLocationCallback.valid() && !fileLocationCallback->useFileCache()) fileCache = 0; cacheNodes = (dr_loadOptions->getObjectCacheHint() & osgDB::Options::CACHE_NODES)!=0; if (cacheNodes) { //OSG_NOTICE<<"Checking main ObjectCache"< objectFromCache = osgDB::Registry::instance()->getRefFromObjectCache(fileName); // if no object with fileName in ObjectCache then try the filename appropriate for fileCache if (!objectFromCache && (fileCache.valid() && fileCache->isFileAppropriateForFileCache(fileName))) { if (fileCache->existsInCache(fileName)) { objectFromCache = osgDB::Registry::instance()->getRefFromObjectCache(fileCache->createCacheFileName(fileName)); } } osg::Node* modelFromCache = dynamic_cast(objectFromCache.get()); if (modelFromCache) { //OSG_NOTICE<<"Found object in cache "< drLock(_pager->_dr_mutex); databaseRequest->_loadedModel = modelFromCache; } // move the request to the dataToMerge list so it can be merged during the update phase of the frame. { OpenThreads::ScopedLock listLock( _pager->_dataToMergeList->_requestMutex); _pager->_dataToMergeList->addNoLock(databaseRequest.get()); databaseRequest = 0; } // skip the rest of the do/while loop as we have done all the processing we need to do. continue; } else { //OSG_NOTICE<<"Not Found object in cache "< drLock(_pager->_dr_mutex); databaseRequest->_objectCache = new ObjectCache; dr_loadOptions->setObjectCache(databaseRequest->_objectCache.get()); } } // check if databaseRequest is still relevant if ((_pager->_frameNumber-frameNumberLastRequest)<=1) { // now check to see if this request is appropriate for this thread switch(_mode) { case(HANDLE_ALL_REQUESTS): { // do nothing as this thread can handle the load if (fileCache.valid() && fileCache->isFileAppropriateForFileCache(fileName)) { if (fileCache->existsInCache(fileName)) { readFromFileCache = true; } } break; } case(HANDLE_NON_HTTP): { // check the cache first bool isHighLatencyFileRequest = false; if (fileLocationCallback.valid()) { isHighLatencyFileRequest = fileLocationCallback->fileLocation(fileName, dr_loadOptions.get()) == FileLocationCallback::REMOTE_FILE; } else if (fileCache.valid() && fileCache->isFileAppropriateForFileCache(fileName)) { isHighLatencyFileRequest = true; } if (isHighLatencyFileRequest) { if (fileCache.valid() && fileCache->existsInCache(fileName)) { readFromFileCache = true; } else { OSG_INFO<<_name<<": Passing http requests over "<add(databaseRequest.get()); databaseRequest = 0; } } break; } case(HANDLE_ONLY_HTTP): { // accept all requests, as we'll assume only high latency requests will have got here. break; } } } else { databaseRequest = 0; } } if (databaseRequest.valid()) { // load the data, note safe to write to the databaseRequest since once // it is created this thread is the only one to write to the _loadedModel pointer. //OSG_NOTICE<<"In DatabasePager thread readNodeFile("<_fileName<<")"<tick(); // assume that readNode is thread safe... ReaderWriter::ReadResult rr = readFromFileCache ? fileCache->readNode(fileName, dr_loadOptions.get(), false) : Registry::instance()->readNode(fileName, dr_loadOptions.get(), false); osg::ref_ptr loadedModel; if (rr.validNode()) loadedModel = rr.getNode(); if (rr.error()) OSG_WARN<<"Error in reading file "<isFileAppropriateForFileCache(fileName) && !readFromFileCache) { fileCache->writeNode(*(loadedModel), fileName, dr_loadOptions.get()); } { OpenThreads::ScopedLock drLock(_pager->_dr_mutex); if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)>1) { OSG_INFO<<_name<<": Warning DatabaseRquest no longer required."<delta_m(before,osg::Timer::instance()->tick())<<" ms"<getBound(); bool loadedObjectsNeedToBeCompiled = false; osg::ref_ptr compileSet = 0; if (!rr.loadedFromCache()) { // find all the compileable rendering objects DatabasePager::FindCompileableGLObjectsVisitor stateToCompile(_pager, _pager->getMarkerObject()); loadedModel->accept(stateToCompile); loadedObjectsNeedToBeCompiled = _pager->_doPreCompile && _pager->_incrementalCompileOperation.valid() && _pager->_incrementalCompileOperation->requiresCompile(stateToCompile); // move the databaseRequest from the front of the fileRequest to the end of // dataToCompile or dataToMerge lists. if (loadedObjectsNeedToBeCompiled) { // OSG_NOTICE<<"Using IncrementalCompileOperation"<buildCompileMap(_pager->_incrementalCompileOperation->getContextSet(), stateToCompile); compileSet->_compileCompletedCallback = new DatabasePagerCompileCompletedCallback(_pager, databaseRequest.get()); _pager->_incrementalCompileOperation->add(compileSet.get(), false); } } else { OSG_NOTICE<<"Loaded from ObjectCache"< drLock(_pager->_dr_mutex); databaseRequest->_loadedModel = loadedModel; databaseRequest->_compileSet = compileSet; } // Dereference the databaseRequest while the queue is // locked. This prevents the request from being // deleted at an unpredictable time within // addLoadedDataToSceneGraph. if (loadedObjectsNeedToBeCompiled) { OpenThreads::ScopedLock listLock( _pager->_dataToCompileList->_requestMutex); _pager->_dataToCompileList->addNoLock(databaseRequest.get()); databaseRequest = 0; } else { OpenThreads::ScopedLock listLock( _pager->_dataToMergeList->_requestMutex); _pager->_dataToMergeList->addNoLock(databaseRequest.get()); databaseRequest = 0; } } // _pager->_dataToCompileList->pruneOldRequestsAndCheckIfEmpty(); } else { OpenThreads::Thread::YieldCurrentThread(); } // go to sleep till our the next time our thread gets scheduled. if (firstTime) { // do a yield to get round a peculiar thread hang when testCancel() is called // in certain circumstances - of which there is no particular pattern. YieldCurrentThread(); firstTime = false; } } while (!testCancel() && !_done); } DatabasePager::DatabasePager() { //OSG_INFO<<"Constructing DatabasePager()"<getNumOfDatabaseThreadsHint(), osg::DisplaySettings::instance()->getNumOfHttpDatabaseThreadsHint()); str = getenv("OSG_DATABASE_PAGER_PRIORITY"); if (str) { if (strcmp(str,"DEFAULT")==0) { setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_DEFAULT); } else if (strcmp(str,"MIN")==0) { setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MIN); } else if (strcmp(str,"LOW")==0) { setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW); } else if (strcmp(str,"NOMINAL")==0) { setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_NOMINAL); } else if (strcmp(str,"HIGH")==0) { setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_HIGH); } else if (strcmp(str,"MAX")==0) { setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MAX); } } _activePagedLODList = new SetBasedPagedLODList; } DatabasePager::DatabasePager(const DatabasePager& rhs) { //OSG_INFO<<"Constructing DatabasePager(const DatabasePager& )"<setName("HasBeenByStateToCompileProcessedMarker"); _startThreadCalled = false; _done = false; _acceptNewRequests = true; _databasePagerThreadPaused = false; _numFramesActive = 0; _frameNumber.exchange(0); _drawablePolicy = rhs._drawablePolicy; _assignPBOToImages = rhs._assignPBOToImages; _changeAutoUnRef = rhs._changeAutoUnRef; _valueAutoUnRef = rhs._valueAutoUnRef; _changeAnisotropy = rhs._changeAnisotropy; _valueAnisotropy = rhs._valueAnisotropy; _deleteRemovedSubgraphsInDatabaseThread = rhs._deleteRemovedSubgraphsInDatabaseThread; _targetMaximumNumberOfPageLOD = rhs._targetMaximumNumberOfPageLOD; _doPreCompile = rhs._doPreCompile; _fileRequestQueue = new ReadQueue(this,"fileRequestQueue"); _httpRequestQueue = new ReadQueue(this,"httpRequestQueue"); _dataToCompileList = new RequestQueue(this); _dataToMergeList = new RequestQueue(this); for(DatabaseThreadList::const_iterator dt_itr = rhs._databaseThreads.begin(); dt_itr != rhs._databaseThreads.end(); ++dt_itr) { _databaseThreads.push_back(new DatabaseThread(**dt_itr,this)); } _activePagedLODList = rhs._activePagedLODList->clone(); #if 1 // need to set the display list manager to be able to reuse display lists osg::Drawable::setMinimumNumberOfDisplayListsToRetainInCache(100); #else // need to set the display list manager to be able to reuse display lists osg::Drawable::setMinimumNumberOfDisplayListsToRetainInCache(0); #endif // initialize the stats variables resetStats(); } void DatabasePager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico) { _incrementalCompileOperation = ico; if (_incrementalCompileOperation.valid()) _markerObject = _incrementalCompileOperation->getMarkerObject(); } DatabasePager::~DatabasePager() { // cancel the threads cancel(); // destruct all the threads _databaseThreads.clear(); // destruct all the queues _fileRequestQueue = 0; _httpRequestQueue = 0; _dataToCompileList = 0; _dataToMergeList = 0; // remove reference to the ICO _incrementalCompileOperation = 0; //_activePagedLODList; //_inactivePagedLODList; } osg::ref_ptr& DatabasePager::prototype() { static osg::ref_ptr s_DatabasePager = new DatabasePager; return s_DatabasePager; } OSG_INIT_SINGLETON_PROXY(ProxyInitDatabasePager, DatabasePager::prototype()) DatabasePager* DatabasePager::create() { return DatabasePager::prototype().valid() ? DatabasePager::prototype()->clone() : new DatabasePager; } void DatabasePager::setUpThreads(unsigned int totalNumThreads, unsigned int numHttpThreads) { _databaseThreads.clear(); unsigned int numGeneralThreads = numHttpThreads < totalNumThreads ? totalNumThreads - numHttpThreads : 1; if (numHttpThreads==0) { for(unsigned int i=0; istartThread(); } return pos; } int DatabasePager::setSchedulePriority(OpenThreads::Thread::ThreadPriority priority) { int result = 0; for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin(); dt_itr != _databaseThreads.end(); ++dt_itr) { result = (*dt_itr)->setSchedulePriority(priority); } return result; } bool DatabasePager::isRunning() const { for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin(); dt_itr != _databaseThreads.end(); ++dt_itr) { if ((*dt_itr)->isRunning()) return true; } return false; } int DatabasePager::cancel() { int result = 0; for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin(); dt_itr != _databaseThreads.end(); ++dt_itr) { (*dt_itr)->setDone(true); } // release the queue blocks in case they are holding up thread cancellation. _fileRequestQueue->release(); _httpRequestQueue->release(); for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin(); dt_itr != _databaseThreads.end(); ++dt_itr) { (*dt_itr)->cancel(); } _done = true; _startThreadCalled = false; return result; } void DatabasePager::clear() { _fileRequestQueue->clear(); _httpRequestQueue->clear(); _dataToCompileList->clear(); _dataToMergeList->clear(); // note, no need to use a mutex as the list is only accessed from the update thread. _activePagedLODList->clear(); // ?? // _activeGraphicsContexts } void DatabasePager::resetStats() { // initialize the stats variables _minimumTimeToMergeTile = DBL_MAX; _maximumTimeToMergeTile = -DBL_MAX; _totalTimeToMergeTiles = 0.0; _numTilesMerges = 0; } bool DatabasePager::getRequestsInProgress() const { if (getFileRequestListSize()>0) return true; if (getDataToCompileListSize()>0) { return true; } if (getDataToMergeListSize()>0) return true; for(DatabaseThreadList::const_iterator itr = _databaseThreads.begin(); itr != _databaseThreads.end(); ++itr) { if ((*itr)->getActive()) return true; } return false; } void DatabasePager::requestNodeFile(const std::string& fileName, osg::NodePath& nodePath, float priority, const osg::FrameStamp* framestamp, osg::ref_ptr& databaseRequestRef, const osg::Referenced* options) { osgDB::Options* loadOptions = dynamic_cast(const_cast(options)); if (!loadOptions) { loadOptions = Registry::instance()->getOptions(); } else { // OSG_NOTICE<<"options from requestNodeFile "<asGroup(); if (!group) { OSG_NOTICE<<"Warning: DatabasePager::requestNodeFile(..) passed NodePath without group as last node in path, so nowhere to attach new subgraph to."<asTerrain()) terrain = *itr; } double timestamp = framestamp?framestamp->getReferenceTime():0.0; unsigned int frameNumber = framestamp?framestamp->getFrameNumber():static_cast(_frameNumber); // #define WITH_REQUESTNODEFILE_TIMING #ifdef WITH_REQUESTNODEFILE_TIMING osg::Timer_t start_tick = osg::Timer::instance()->tick(); static int previousFrame = -1; static double totalTime = 0.0; if (previousFrame!=frameNumber) { OSG_NOTICE<<"requestNodeFiles for "<_valid = true; databaseRequest->_frameNumberLastRequest = frameNumber; databaseRequest->_timestampLastRequest = timestamp; databaseRequest->_priorityLastRequest = priority; ++(databaseRequest->_numOfRequests); foundEntry = true; if (databaseRequestRef->referenceCount()==1) { OSG_INFO<<"DatabasePager::requestNodeFile("<_frameNumberLastRequest = frameNumber; databaseRequest->_timestampLastRequest = timestamp; databaseRequest->_priorityLastRequest = priority; databaseRequest->_group = group; databaseRequest->_terrain = terrain; databaseRequest->_loadOptions = loadOptions; databaseRequest->_objectCache = 0; requeue = true; } } } if (requeue) _fileRequestQueue->add(databaseRequest); } if (!foundEntry) { OSG_INFO<<"In DatabasePager::requestNodeFile("< lock(_fileRequestQueue->_requestMutex); if (!databaseRequestRef.valid() || databaseRequestRef->referenceCount()==1) { osg::ref_ptr databaseRequest = new DatabaseRequest; databaseRequestRef = databaseRequest.get(); databaseRequest->_valid = true; databaseRequest->_fileName = fileName; databaseRequest->_frameNumberFirstRequest = frameNumber; databaseRequest->_timestampFirstRequest = timestamp; databaseRequest->_priorityFirstRequest = priority; databaseRequest->_frameNumberLastRequest = frameNumber; databaseRequest->_timestampLastRequest = timestamp; databaseRequest->_priorityLastRequest = priority; databaseRequest->_group = group; databaseRequest->_terrain = terrain; databaseRequest->_loadOptions = loadOptions; databaseRequest->_objectCache = 0; _fileRequestQueue->addNoLock(databaseRequest.get()); } } if (!_startThreadCalled) { OpenThreads::ScopedLock lock(_run_mutex); if (!_startThreadCalled) { _startThreadCalled = true; _done = false; OSG_INFO<<"DatabasePager::startThread()"<getNumOfDatabaseThreadsHint(), osg::DisplaySettings::instance()->getNumOfHttpDatabaseThreadsHint()); } for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin(); dt_itr != _databaseThreads.end(); ++dt_itr) { (*dt_itr)->startThread(); } } } #ifdef WITH_REQUESTNODEFILE_TIMING totalTime += osg::Timer::instance()->delta_m(start_tick, osg::Timer::instance()->tick()); #endif } void DatabasePager::signalBeginFrame(const osg::FrameStamp* framestamp) { #if 0 OSG_NOTICE<<"DatabasePager : _fileRequestQueue->size()="<<_fileRequestQueue->size() <<", _httpRequestQueue->size()= "<<_httpRequestQueue->size() <<", _dataToCompileList->size()= "<<_dataToCompileList->size() <<", _dataToMergeList->size()= "<<_dataToMergeList->size()<pruneOldRequestsAndCheckIfEmpty(); //OSG_INFO << "signalBeginFrame "<getFrameNumber()<<">>>>>>>>>>>>>>>>"<getFrameNumber()); } //else OSG_INFO << "signalBeginFrame >>>>>>>>>>>>>>>>"< lock(_fileRequestQueue->_requestMutex); _fileRequestQueue->updateBlock(); } { OpenThreads::ScopedLock lock(_httpRequestQueue->_requestMutex); _httpRequestQueue->updateBlock(); } } bool DatabasePager::requiresUpdateSceneGraph() const { return !(_dataToMergeList->empty()); } void DatabasePager::updateSceneGraph(const osg::FrameStamp& frameStamp) { #define UPDATE_TIMING 0 #if UPDATE_TIMING osg::ElapsedTime timer; double timeFor_removeExpiredSubgraphs, timeFor_addLoadedDataToSceneGraph; #endif { removeExpiredSubgraphs(frameStamp); #if UPDATE_TIMING timeFor_removeExpiredSubgraphs = timer.elapsedTime_m(); #endif addLoadedDataToSceneGraph(frameStamp); #if UPDATE_TIMING timeFor_addLoadedDataToSceneGraph = timer.elapsedTime_m() - timeFor_removeExpiredSubgraphs; #endif } #if UPDATE_TIMING double elapsedTime = timer.elapsedTime_m(); if (elapsedTime>0.4) { OSG_NOTICE<<"DatabasePager::updateSceneGraph() total time = "<_fileName<<" after "<_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<_timestampFirstRequest; if (timeToMerge<_minimumTimeToMergeTile) _minimumTimeToMergeTile = timeToMerge; if (timeToMerge>_maximumTimeToMergeTile) _maximumTimeToMergeTile = timeToMerge; _totalTimeToMergeTiles += timeToMerge; ++_numTilesMerges; } else { OSG_INFO<<"DatabasePager::addLoadedDataToSceneGraph() node in parental chain deleted, discarding subgaph."<_loadedModel = 0; // OSG_NOTICE<<"curr = "<delta_m(before,mid)<<"ms,\t"<< osg::Timer::instance()->delta_m(mid,last)<<"ms"<< " objects"<tick(); // numPagedLODs >= actual number of PagedLODs. There can be // invalid observer pointers in _activePagedLODList. unsigned int numPagedLODs = _activePagedLODList->size(); osg::Timer_t end_a_Tick = osg::Timer::instance()->tick(); double time_a = osg::Timer::instance()->delta_m(startTick,end_a_Tick); s_total_iter_stage_a += 1.0; s_total_time_stage_a += time_a; if (s_total_max_stage_a0) _activePagedLODList->removeExpiredChildren( numToPrune, expiryTime, expiryFrame, childrenRemoved, false); numToPrune = _activePagedLODList->size() - _targetMaximumNumberOfPageLOD; if (numToPrune>0) _activePagedLODList->removeExpiredChildren( numToPrune, expiryTime, expiryFrame, childrenRemoved, true); osg::Timer_t end_b_Tick = osg::Timer::instance()->tick(); double time_b = osg::Timer::instance()->delta_m(end_a_Tick,end_b_Tick); s_total_iter_stage_b += 1.0; s_total_time_stage_b += time_b; if (s_total_max_stage_b obs_ptr(&plod); _activePagedLODList.insertPagedLOD(obs_ptr); traverse(plod); } DatabasePager::PagedLODList& _activePagedLODList; unsigned int _frameNumber; protected: FindPagedLODsVisitor& operator = (const FindPagedLODsVisitor&) { return *this; } }; void DatabasePager::registerPagedLODs(osg::Node* subgraph, unsigned int frameNumber) { if (!subgraph) return; FindPagedLODsVisitor fplv(*_activePagedLODList, frameNumber); subgraph->accept(fplv); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/ImageOptions.cpp0000644000175000017500000000064413151044751023755 0ustar albertoalberto#include using namespace osgDB; ImageOptions::ImageOptions() { init(); } ImageOptions::ImageOptions(const std::string& str) { init(); _str = str; } void ImageOptions::init() { _sourceImageSamplingMode = NEAREST; _sourceImageWindowMode = ALL_IMAGE; _destinationImageWindowMode = ALL_IMAGE; _destinationDataType = GL_NONE; _destinationPixelFormat = GL_NONE; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Registry.cpp0000644000175000017500000016712213151044751023174 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__sgi) #include #elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__) #include using std::tolower; #endif #ifdef OSG_LIBRARY_POSTFIX #define OSG_LIBRARY_POSTFIX_WITH_QUOTES ADDQUOTES(OSG_LIBRARY_POSTFIX) #else #define OSG_LIBRARY_POSTFIX_WITH_QUOTES "" #endif using namespace osg; using namespace osgDB; #if !defined(WIN32) || defined(__CYGWIN__) static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH [:path]..","Paths for locating datafiles"); static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH [:path]..","Paths for locating libraries/ plugins"); #else static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH [;path]..","Paths for locating datafiles"); static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH [;path]..","Paths for locating libraries/ plugins"); #endif static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry."); // from MimeTypes.cpp extern const char* builtinMimeTypeExtMappings[]; class Registry::AvailableReaderWriterIterator { public: AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList, OpenThreads::ReentrantMutex& pluginMutex): _rwList(rwList), _pluginMutex(pluginMutex) {} ReaderWriter& operator * () { return *get(); } ReaderWriter* operator -> () { return get(); } bool valid() { return get()!=0; } void operator ++() { _rwUsed.insert(get()); } protected: AvailableReaderWriterIterator& operator = (const AvailableReaderWriterIterator&) { return *this; } Registry::ReaderWriterList& _rwList; OpenThreads::ReentrantMutex& _pluginMutex; std::set _rwUsed; ReaderWriter* get() { OpenThreads::ScopedLock lock(_pluginMutex); Registry::ReaderWriterList::iterator itr=_rwList.begin(); for(;itr!=_rwList.end();++itr) { if (_rwUsed.find(itr->get())==_rwUsed.end()) { return itr->get(); } } return 0; } }; class Registry::AvailableArchiveIterator { public: AvailableArchiveIterator(Registry::ArchiveCache& archives, OpenThreads::ReentrantMutex& mutex): _archives(archives), _mutex(mutex) {} Archive& operator * () { return *get(); } Archive* operator -> () { return get(); } bool valid() { return get()!=0; } void operator ++() { _archivesUsed.insert(get()); } protected: AvailableArchiveIterator& operator = (const AvailableArchiveIterator&) { return *this; } Registry::ArchiveCache& _archives; OpenThreads::ReentrantMutex& _mutex; std::set _archivesUsed; Archive* get() { OpenThreads::ScopedLock lock(_mutex); Registry::ArchiveCache::iterator itr=_archives.begin(); for(;itr!=_archives.end();++itr) { if (_archivesUsed.find(itr->second.get())==_archivesUsed.end()) { return itr->second.get(); } } return 0; } }; #if 0 // temporary test of autoregistering, not compiled by default. enum Methods { SET_1, SET_2, END }; typedef std::pair MethodPair; class Proxy { public: Proxy(MethodPair* methods) { std::cout<<"methods "< s_registry = new Registry; if (erase) { s_registry->destruct(); s_registry = 0; } return s_registry.get(); // will return NULL on erase } OSG_INIT_SINGLETON_PROXY(ProxyInitRegistry, Registry::instance()) // definition of the Registry Registry::Registry() { // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify(). // OSG_INFO << "Constructing osg::Registry"< void Registry::initDataFilePathList() { FilePathList filepath; // // set up data file paths // char *ptr; if( (ptr = getenv( "OSG_FILE_PATH" )) ) { //OSG_NOTIFY(DEBUG_INFO) << "OSG_FILE_PATH("<addCommandLineOption("-l ","Load the plugin"); arguments.getApplicationUsage()->addCommandLineOption("-e ","Load the plugin associated with handling files with specified extension"); arguments.getApplicationUsage()->addCommandLineOption("-O ","Provide an option string to reader/writers used to load databases"); } std::string value; while(arguments.read("-l",value)) { loadLibrary(value); } while(arguments.read("-e",value)) { std::string libName = createLibraryNameForExtension(value); loadLibrary(libName); } while(arguments.read("-O",value)) { setOptions(new Options(value)); } } void Registry::addReaderWriter(ReaderWriter* rw) { if (rw==0L) return; // OSG_NOTIFY(INFO) << "osg::Registry::addReaderWriter("<className()<<")"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); _rwList.push_back(rw); } void Registry::removeReaderWriter(ReaderWriter* rw) { if (rw==0L) return; // OSG_NOTIFY(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw); if (rwitr!=_rwList.end()) { _rwList.erase(rwitr); } } ImageProcessor* Registry::getImageProcessor() { { OpenThreads::ScopedLock lock(_pluginMutex); if (!_ipList.empty()) { return _ipList.front().get(); } } return getImageProcessorForExtension("nvtt"); } ImageProcessor* Registry::getImageProcessorForExtension(const std::string& ext) { { OpenThreads::ScopedLock lock(_pluginMutex); if (!_ipList.empty()) { return _ipList.front().get(); } } std::string libraryName = createLibraryNameForExtension(ext); OSG_NOTICE << "Now checking for plug-in "< lock(_pluginMutex); if (!_ipList.empty()) { OSG_NOTICE << "Loaded plug-in "<className()<<")"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); _ipList.push_back(ip); } void Registry::removeImageProcessor(ImageProcessor* ip) { if (ip==0L) return; OSG_NOTIFY(NOTICE) << "osg::Registry::removeImageProcessor();"<< std::endl; OpenThreads::ScopedLock lock(_pluginMutex); ImageProcessorList::iterator ipitr = std::find(_ipList.begin(),_ipList.end(),ip); if (ipitr!=_ipList.end()) { _ipList.erase(ipitr); } } void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt) { _extAliasMap[mapExt] = toExt; } void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt) { _mimeTypeExtMap[fromMimeType] = toExt; } bool Registry::readPluginAliasConfigurationFile( const std::string& file ) { std::string fileName = osgDB::findDataFile( file ); if (fileName.empty()) { OSG_NOTIFY( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl; return false; } osgDB::ifstream ifs; ifs.open( fileName.c_str() ); if (!ifs.good()) { OSG_NOTIFY( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl; return false; } int lineNum( 0 ); while (ifs.good()) { std::string raw; ++lineNum; std::getline( ifs, raw ); std::string ln = trim( raw ); if (ln.empty()) continue; if (ln[0] == '#') continue; std::string::size_type spIdx = ln.find_first_of( " \t" ); if (spIdx == ln.npos) { // mapExt and toExt must be on the same line, separated by a space. OSG_NOTIFY( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl; continue; } const std::string mapExt = trim( ln.substr( 0, spIdx ) ); const std::string toExt = trim( ln.substr( spIdx+1 ) ); addFileExtensionAlias( mapExt, toExt ); } return true; } std::string Registry::trim( const std::string& str ) { if (!str.size()) return str; std::string::size_type first = str.find_first_not_of( " \t" ); std::string::size_type last = str.find_last_not_of( " \t\r\n" ); if ((first==str.npos) || (last==str.npos)) return std::string( "" ); return str.substr( first, last-first+1 ); } std::string Registry::createLibraryNameForFile(const std::string& fileName) { return createLibraryNameForExtension(getFileExtension(fileName)); } std::string Registry::createLibraryNameForExtension(const std::string& ext) { std::string lowercase_ext; for(std::string::const_iterator sitr=ext.begin(); sitr!=ext.end(); ++sitr) { lowercase_ext.push_back(tolower(*sitr)); } ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext); if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second); std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/"); #if defined(__CYGWIN__) return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(__MINGW32__) return prepend+"mingw_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(WIN32) return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif macintosh return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES; #else return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+ADDQUOTES(OSG_PLUGIN_EXTENSION); #endif } std::string Registry::createLibraryNameForNodeKit(const std::string& name) { #if defined(__CYGWIN__) return "cyg"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(__MINGW32__) return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif defined(WIN32) return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll"; #elif macintosh return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES; #else return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES + ADDQUOTES(OSG_PLUGIN_EXTENSION); #endif } Registry::LoadStatus Registry::loadLibrary(const std::string& fileName) { OpenThreads::ScopedLock lock(_pluginMutex); DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED; _openingLibrary=true; DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName); _openingLibrary=false; if (dl) { _dlList.push_back(dl); return LOADED; } return NOT_LOADED; } bool Registry::closeLibrary(const std::string& fileName) { OpenThreads::ScopedLock lock(_pluginMutex); DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) { _dlList.erase(ditr); return true; } return false; } void Registry::closeAllLibraries() { // OSG_NOTICE<<"Registry::closeAllLibraries()"< lock(_pluginMutex); _dlList.clear(); } Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName) { DynamicLibraryList::iterator ditr = _dlList.begin(); for(;ditr!=_dlList.end();++ditr) { if ((*ditr)->getName()==fileName) return ditr; } return _dlList.end(); } DynamicLibrary* Registry::getLibrary(const std::string& fileName) { OpenThreads::ScopedLock lock(_pluginMutex); DynamicLibraryList::iterator ditr = getLibraryItr(fileName); if (ditr!=_dlList.end()) return ditr->get(); else return NULL; } ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext) { // record the existing reader writer. std::set rwOriginal; OpenThreads::ScopedLock lock(_pluginMutex); // first attempt one of the installed loaders for(ReaderWriterList::iterator itr=_rwList.begin(); itr!=_rwList.end(); ++itr) { rwOriginal.insert(itr->get()); if((*itr)->acceptsExtension(ext)) return (*itr).get(); } // now look for a plug-in to load the file. std::string libraryName = createLibraryNameForExtension(ext); OSG_NOTIFY(INFO) << "Now checking for plug-in "<get())==rwOriginal.end()) { if((*itr)->acceptsExtension(ext)) return (*itr).get(); } } } return NULL; } ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType) { MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType ); return i != _mimeTypeExtMap.end()? getReaderWriterForExtension( i->second ) : NULL; } #if 0 struct concrete_wrapper: basic_type_wrapper { virtual ~concrete_wrapper() {} concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {} bool matches(const osg::Object *proto) const { return myobj_->isSameKindAs(proto); } const osg::Object *myobj_; }; #endif struct Registry::ReadObjectFunctor : public Registry::ReadFunctor { ReadObjectFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); } virtual bool isValid(osg::Object* object) const { return object!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadObjectFunctor(filename, options); } }; struct Registry::ReadImageFunctor : public Registry::ReadFunctor { ReadImageFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readImage(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadImageFunctor(filename, options); } }; struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor { ReadHeightFieldFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadHeightFieldFunctor(filename, options); } }; struct Registry::ReadNodeFunctor : public Registry::ReadFunctor { ReadNodeFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadNodeFunctor(filename, options); } }; struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor { ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options): ReadFunctor(filename,options), _status(status), _indexBlockSizeHint(indexBlockSizeHint) {} ReaderWriter::ArchiveStatus _status; unsigned int _indexBlockSizeHint; virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadArchiveFunctor(filename, _status, _indexBlockSizeHint, options); } }; struct Registry::ReadShaderFunctor : public Registry::ReadFunctor { ReadShaderFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readShader(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadShaderFunctor(filename, options); } }; struct Registry::ReadScriptFunctor : public Registry::ReadFunctor { ReadScriptFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {} virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readScript(_filename, _options); } virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validScript(); } virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadScriptFunctor(filename, options); } }; void Registry::addArchiveExtension(const std::string ext) { for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin(); aitr!=_archiveExtList.end(); ++aitr) { if ( (*aitr) == ext) // extension already in archive extension list return; } _archiveExtList.push_back(ext); } std::string Registry::findDataFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity) { if (filename.empty()) return filename; // if data file contains a server address then we can't find it in local directories so return empty string. if (containsServerAddress(filename)) return std::string(); bool absolutePath = osgDB::isAbsolutePath(filename); if (absolutePath && fileExists(filename)) { OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl; return filename; } std::string fileFound; bool pathsContainsCurrentWorkingDirectory = false; if (options && !options->getDatabasePathList().empty()) { fileFound = findFileInPath(filename, options->getDatabasePathList(), caseSensitivity); if (!fileFound.empty()) return fileFound; if (osgDB::containsCurrentWorkingDirectoryReference(options->getDatabasePathList())) { pathsContainsCurrentWorkingDirectory = true; } } const FilePathList& filepaths = Registry::instance()->getDataFilePathList(); if (!filepaths.empty()) { fileFound = findFileInPath(filename, filepaths, caseSensitivity); if (!fileFound.empty()) return fileFound; if (!pathsContainsCurrentWorkingDirectory && osgDB::containsCurrentWorkingDirectoryReference(filepaths)) { pathsContainsCurrentWorkingDirectory = true; } } if (!absolutePath && !pathsContainsCurrentWorkingDirectory) { // check current working directory if (fileExists(filename)) { return filename; } } // if a directory is included in the filename, get just the (simple) filename itself and try that std::string simpleFileName = getSimpleFileName(filename); if (simpleFileName!=filename) { if(fileExists(simpleFileName)) { OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << simpleFileName << std::endl; return simpleFileName; } if (options && !options->getDatabasePathList().empty()) { fileFound = findFileInPath(simpleFileName, options->getDatabasePathList(), caseSensitivity); if (!fileFound.empty()) return fileFound; } if (!filepaths.empty()) { fileFound = findFileInPath(simpleFileName, filepaths,caseSensitivity); if (!fileFound.empty()) return fileFound; } } // return empty string. return std::string(); } std::string Registry::findLibraryFileImplementation(const std::string& filename, const Options* /*options*/, CaseSensitivity caseSensitivity) { if (filename.empty()) return filename; const FilePathList& filepath = Registry::instance()->getLibraryFilePathList(); std::string fileFound = findFileInPath(filename, filepath,caseSensitivity); if (!fileFound.empty()) return fileFound; if(fileExists(filename)) { OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl; return filename; } // if a directory is included in the filename, get just the (simple) filename itself and try that std::string simpleFileName = getSimpleFileName(filename); if (simpleFileName!=filename) { std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity); if (!fileFound.empty()) return fileFound; } // failed return empty string. return std::string(); } ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor) { for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin(); aitr!=_archiveExtList.end(); ++aitr) { std::string archiveExtension = "." + (*aitr); std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/'); if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\'); if (positionArchive!=std::string::npos) { std::string::size_type endArchive = positionArchive + archiveExtension.length(); std::string archiveName( readFunctor._filename.substr(0,endArchive)); std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos)); OSG_INFO<<"Contains archive : "< options = readFunctor._options ? readFunctor._options->cloneOptions() : new osgDB::ReaderWriter::Options; options->setDatabasePath(archiveName); std::auto_ptr rf(readFunctor.cloneType(fileName, options.get())); result = rf->doRead(*archive); if (rf->isValid(result)) { OSG_INFO<<"Read object from archive"< Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::ReadResult rr = readFunctor.doRead(*itr); if (readFunctor.isValid(rr)) return rr; else results.push_back(rr); } // check loaded archives. AvailableArchiveIterator aaitr(_archiveCache, _archiveCacheMutex); for(;aaitr.valid();++aaitr) { ReaderWriter::ReadResult rr = readFunctor.doRead(*aaitr); if (readFunctor.isValid(rr)) return rr; else { // don't pass on FILE_NOT_FOUND results as we don't want to prevent non archive plugins that haven't been // loaded yet from getting a chance to test for the presence of the file. if (rr.status()!=ReaderWriter::ReadResult::FILE_NOT_FOUND) results.push_back(rr); } } // now look for a plug-in to load the file. std::string libraryName = createLibraryNameForFile(readFunctor._filename); if (loadLibrary(libraryName)!=NOT_LOADED) { for(;itr.valid();++itr) { ReaderWriter::ReadResult rr = readFunctor.doRead(*itr); if (readFunctor.isValid(rr)) return rr; else results.push_back(rr); } } //If the filename contains a server address and wasn't loaded by any of the plugins, try to find a plugin which supports the server //protocol and supports wildcards. If not successfully use curl as a last fallback if (containsServerAddress(readFunctor._filename)) { ReaderWriter* rw = getReaderWriterForProtocolAndExtension( osgDB::getServerProtocol(readFunctor._filename), osgDB::getFileExtension(readFunctor._filename) ); if (rw) { return readFunctor.doRead(*rw); } else { return ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server."); } } if (results.empty()) { return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_READING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::ReadResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::ReadResult::FILE_NOT_HANDLED): result.message() = "Warning: reading \""+readFunctor._filename+"\" not supported."; break; case(ReaderWriter::ReadResult::FILE_NOT_FOUND): result.message() = "Warning: could not find file \""+readFunctor._filename+"\"."; break; case(ReaderWriter::ReadResult::ERROR_IN_READING_FILE): result.message() = "Warning: Error in reading to \""+readFunctor._filename+"\"."; break; default: break; } } return result; } ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,Options::CacheHintOptions cacheHint) { std::string file(readFunctor._filename); bool useObjectCache = false; const Options* options = readFunctor._options; ObjectCache* optionsCache = options ? options->getObjectCache() : 0; //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here if ((optionsCache || _objectCache.valid()) && cacheHint!=Options::CACHE_ARCHIVES) { useObjectCache= options ? (options->getObjectCacheHint()&cacheHint)!=0: false; } if (useObjectCache) { // search for entry in the object cache. osg::ref_ptr object = optionsCache ? optionsCache->getRefFromObjectCache(file) : 0; if (!object && _objectCache.valid()) object = _objectCache->getRefFromObjectCache(file); if (object.valid()) { if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); else return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); } ReaderWriter::ReadResult rr = read(readFunctor); if (rr.validObject()) { // search AGAIN for entry in the object cache. object = _objectCache->getRefFromObjectCache(file); if (object.valid()) { if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); else { return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); } } // update cache with new entry. if (optionsCache) optionsCache->addEntryToObjectCache(file, rr.getObject(), 0.0); else if (_objectCache.valid()) _objectCache->addEntryToObjectCache(file, rr.getObject(), 0.0); } else { OSG_INFO<<"No valid object found for "< archive = getRefFromArchiveCache(fileName); if (archive.valid()) return archive.get(); ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),Options::CACHE_ARCHIVES); // default to using caching archive if no options structure provided, but if options are provided use archives // only if supplied. if (result.validArchive() && (!options || (options->getObjectCacheHint() & Options::CACHE_ARCHIVES)) ) { addToArchiveCache(fileName,result.getArchive()); } return result; } ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadObjectFunctor(fileName, options),Options::CACHE_OBJECTS); } ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const Options* options) { // record the errors reported by readerwriters. typedef std::vector Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): result.message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): result.message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return result; } ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadImageFunctor(fileName, options),Options::CACHE_IMAGES); } ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const Options* options) { // record the errors reported by readerwriters. typedef std::vector Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): result.message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): result.message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return result; } ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadHeightFieldFunctor(fileName, options),Options::CACHE_HEIGHTFIELDS); } ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const Options* options) { // record the errors reported by readerwriters. typedef std::vector Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): result.message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): result.message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return result; } ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const Options* options) { #if 0 osg::Timer_t startTick = osg::Timer::instance()->tick(); ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES); osg::Timer_t endTick = osg::Timer::instance()->tick(); OSG_NOTICE<<"time to load "<delta_m(startTick, endTick)<<"ms"< Results; Results results; // first attempt to write the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): result.message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): result.message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return result; } ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadShaderFunctor(fileName, options),Options::CACHE_SHADERS); } ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const Options* options) { // record the errors reported by readerwriters. typedef std::vector Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } results.clear(); // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): result.message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): result.message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return result; } ReaderWriter::ReadResult Registry::readScriptImplementation(const std::string& fileName,const Options* options) { return readImplementation(ReadScriptFunctor(fileName, options),Options::CACHE_IMAGES); } ReaderWriter::WriteResult Registry::writeScriptImplementation(const Script& image,const std::string& fileName,const Options* options) { // record the errors reported by readerwriters. typedef std::vector Results; Results results; // first attempt to load the file from existing ReaderWriter's AvailableReaderWriterIterator itr(_rwList, _pluginMutex); for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeScript(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } // now look for a plug-in to save the file. std::string libraryName = createLibraryNameForFile(fileName); if (loadLibrary(libraryName)==LOADED) { for(;itr.valid();++itr) { ReaderWriter::WriteResult rr = itr->writeScript(image,fileName,options); if (rr.success()) return rr; else results.push_back(rr); } } if (results.empty()) { return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\"."); } // sort the results so the most relevant (i.e. ERROR_IN_WRITING_FILE is more relevant than FILE_NOT_FOUND) results get placed at the end of the results list. std::sort(results.begin(), results.end()); ReaderWriter::WriteResult result = results.back(); if (result.message().empty()) { switch(result.status()) { case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): result.message() = "Warning: Write to \""+fileName+"\" not supported."; break; case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): result.message() = "Warning: Error in writing to \""+fileName+"\"."; break; default: break; } } return result; } void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { if (_objectCache.valid()) _objectCache->addEntryToObjectCache(filename, object, timestamp); } osg::Object* Registry::getFromObjectCache(const std::string& filename) { return _objectCache.valid() ? _objectCache->getFromObjectCache(filename) : 0; } osg::ref_ptr Registry::getRefFromObjectCache(const std::string& filename) { return _objectCache.valid() ? _objectCache->getRefFromObjectCache(filename) : 0; } void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(const osg::FrameStamp& frameStamp) { if (_objectCache.valid()) _objectCache->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime()); } void Registry::removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp) { double expiryTime = frameStamp.getReferenceTime() - _expiryDelay; if (_objectCache.valid()) _objectCache->removeExpiredObjectsInCache(expiryTime); } void Registry::removeFromObjectCache(const std::string& filename) { if (_objectCache.valid()) _objectCache->removeFromObjectCache(filename); } void Registry::clearObjectCache() { if (_objectCache.valid()) _objectCache->clear(); } void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive) { OpenThreads::ScopedLock lock(_archiveCacheMutex); _archiveCache[fileName] = archive; } /** Remove archive from cache.*/ void Registry::removeFromArchiveCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_archiveCacheMutex); ArchiveCache::iterator itr = _archiveCache.find(fileName); if (itr!=_archiveCache.end()) { _archiveCache.erase(itr); } } osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_archiveCacheMutex); ArchiveCache::iterator itr = _archiveCache.find(fileName); if (itr!=_archiveCache.end()) return itr->second.get(); else return 0; } osg::ref_ptr Registry::getRefFromArchiveCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_archiveCacheMutex); ArchiveCache::iterator itr = _archiveCache.find(fileName); if (itr!=_archiveCache.end()) return itr->second; else return 0; } void Registry::clearArchiveCache() { OpenThreads::ScopedLock lock(_archiveCacheMutex); _archiveCache.clear(); } void Registry::releaseGLObjects(osg::State* state) { if (_objectCache.valid()) _objectCache->releaseGLObjects( state ); if (_sharedStateManager.valid()) _sharedStateManager->releaseGLObjects( state ); } SharedStateManager* Registry::getOrCreateSharedStateManager() { if (!_sharedStateManager) _sharedStateManager = new SharedStateManager; return _sharedStateManager.get(); } void Registry::registerProtocol(const std::string& protocol) { _registeredProtocols.insert( convertToLowerCase(protocol) ); } bool Registry::isProtocolRegistered(const std::string& protocol) { return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end()); } void Registry::getReaderWriterListForProtocol(const std::string& protocol, ReaderWriterList& results) const { for(ReaderWriterList::const_iterator i = _rwList.begin(); i != _rwList.end(); ++i) { if ((*i)->acceptsProtocol(protocol)) results.push_back(*i); } } ReaderWriter* Registry::getReaderWriterForProtocolAndExtension(const std::string& protocol, const std::string& extension) { // try first the registered ReaderWriter ReaderWriter* result = getReaderWriterForExtension(extension); if (result && result->acceptsProtocol(protocol)) return result; result = NULL; ReaderWriterList results; getReaderWriterListForProtocol(protocol, results); for(ReaderWriterList::const_iterator i = results.begin(); i != results.end(); ++i) { // if we have a readerwriter which supports wildcards, save it as a fallback if ((*i)->acceptsExtension("*")) result = i->get(); else if ((*i)->acceptsExtension(extension)) return i->get(); } return result ? result : getReaderWriterForExtension("curl"); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/DatabaseRevisions.cpp0000644000175000017500000001156113151044751024765 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include using namespace osgDB; //////////////////////////////////////////////////////////////////////////////////////////// // // FilelList // FileList::FileList() { } FileList::FileList(const FileList& fileList, const osg::CopyOp & copyop): osg::Object(fileList, copyop), _files(fileList._files) { } FileList::~FileList() { } bool FileList::removeFile(const std::string& filename) { FileNames::iterator itr = _files.find(filename); if (itr==_files.end()) return false; _files.erase(itr); return true; } void FileList::append(FileList* fileList) { for(FileNames::iterator itr = fileList->_files.begin(); itr != fileList->_files.end(); ++itr) { _files.insert(*itr); } } //////////////////////////////////////////////////////////////////////////////////////////// // // DatabaseRevision // DatabaseRevision::DatabaseRevision() { } DatabaseRevision::DatabaseRevision(const DatabaseRevision& revision, const osg::CopyOp & copyop): osg::Object(revision, copyop), _databasePath(revision._databasePath), _filesAdded(revision._filesAdded), _filesRemoved(revision._filesRemoved), _filesModified(revision._filesModified) { } DatabaseRevision::~DatabaseRevision() { } bool DatabaseRevision::isFileBlackListed(const std::string& filename) const { OSG_INFO<<"DatabaseRevision("<=filename.length()) return false; if (filename.compare(0,_databasePath.length(), _databasePath)!=0) return false; std::string localPath(filename, _databasePath.empty() ? 0 : _databasePath.length()+1, std::string::npos); return (_filesRemoved.valid() && _filesRemoved->containsFile(localPath)) || (_filesModified.valid() && _filesModified->containsFile(localPath)); } bool DatabaseRevision::removeFile(const std::string& filename) { bool removed = false; if (_filesAdded.valid()) removed = _filesAdded->removeFile(filename) | removed; if (_filesRemoved.valid()) removed = _filesRemoved->removeFile(filename) | removed; if (_filesModified.valid()) removed = _filesModified->removeFile(filename) | removed; return removed; } //////////////////////////////////////////////////////////////////////////////////////////// // // DatabaseRevisions // DatabaseRevisions::DatabaseRevisions() { } DatabaseRevisions::DatabaseRevisions(const DatabaseRevisions& revisions, const osg::CopyOp & copyop): osg::Object(revisions, copyop), _databasePath(revisions._databasePath), _revisionList(revisions._revisionList) { } DatabaseRevisions::~DatabaseRevisions() { } void DatabaseRevisions::addRevision(DatabaseRevision* revision) { if (!revision) return; for(DatabaseRevisionList::iterator itr = _revisionList.begin(); itr != _revisionList.end(); ++itr) { if (*itr == revision) return; if ((*itr)->getName()==revision->getName()) { (*itr) = revision; return; } } _revisionList.push_back(revision); } void DatabaseRevisions::removeRevision(DatabaseRevision* revision) { for(DatabaseRevisionList::iterator itr = _revisionList.begin(); itr != _revisionList.end(); ++itr) { if (*itr == revision) { _revisionList.erase(itr); return; } } } bool DatabaseRevisions::isFileBlackListed(const std::string& filename) const { for(DatabaseRevisionList::const_iterator itr = _revisionList.begin(); itr != _revisionList.end(); ++itr) { if ((*itr)->isFileBlackListed(filename)) { OSG_INFO<<"File is black listed "<removeFile(filename) | removed; } return removed; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/FileUtils.cpp0000644000175000017500000012107713151044751023263 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // handle TCHAR type on various platforms // #ifndef is inspired by https://svn.apache.org/repos/asf/logging/log4cxx/tags/v0_9_4/include/log4cxx/helpers/tchar.h // defining type as plain char is from unzip.h, line 64 #ifndef TCHAR typedef char TCHAR; #endif // currently this impl is for _all_ platforms, except as defined. // the mac version will change soon to reflect the path scheme under osx, but // for now, the above include is commented out, and the below code takes precedence. #if defined(WIN32) && !defined(__CYGWIN__) #include #define WINBASE_DECLARE_GET_MODULE_HANDLE_EX #include #include #include #include #include // for _mkdir #define mkdir(x,y) _mkdir((x)) #define stat64 _stati64 // set up for windows so acts just like unix access(). #ifndef F_OK #define F_OK 4 #endif #else // unix #if defined( __APPLE__ ) // I'm not sure how we would handle this in raw Darwin // without the AvailablilityMacros. #include //>OSG_IOS //IOS includes #include "TargetConditionals.h" #include #if (TARGET_OS_IPHONE) #include // workaround a bug which appears when compiling for SDK < 4.0 and for the simulator #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) #define stat64 stat #else #if !TARGET_IPHONE_SIMULATOR #define stat64 stat #endif #endif #endif // #include #include #include #if defined(_DARWIN_FEATURE_64_BIT_INODE) #define stat64 stat #endif #endif // set up _S_ISDIR() #if !defined(S_ISDIR) # if defined( _S_IFDIR) && !defined( __S_IFDIR) # define __S_IFDIR _S_IFDIR # endif # define S_ISDIR(mode) (mode&__S_IFDIR) #endif #include #include #include #include #include #include #include #include #include namespace osgDB { #ifdef OSG_USE_UTF8_FILENAME #define OSGDB_STRING_TO_FILENAME(s) osgDB::convertUTF8toUTF16(s) #define OSGDB_FILENAME_TO_STRING(s) osgDB::convertUTF16toUTF8(s) #define OSGDB_FILENAME_TEXT(x) L ## x #define OSGDB_WINDOWS_FUNCT(x) x ## W #define OSGDB_WINDOWS_FUNCT_STRING(x) #x "W" typedef wchar_t filenamechar; typedef std::wstring filenamestring; #else #define OSGDB_STRING_TO_FILENAME(s) s #define OSGDB_FILENAME_TO_STRING(s) s #define OSGDB_FILENAME_TEXT(x) x #define OSGDB_WINDOWS_FUNCT(x) x ## A #define OSGDB_WINDOWS_FUNCT_STRING(x) #x "A" typedef char filenamechar; typedef std::string filenamestring; #endif } FILE* osgDB::fopen(const char* filename, const char* mode) { #ifdef OSG_USE_UTF8_FILENAME return ::_wfopen(convertUTF8toUTF16(filename).c_str(), convertUTF8toUTF16(mode).c_str()); #else return ::fopen(filename, mode); #endif } bool osgDB::makeDirectory( const std::string &path ) { if (path.empty()) { OSG_DEBUG << "osgDB::makeDirectory(): cannot create an empty directory" << std::endl; return false; } struct stat64 stbuf; #ifdef OSG_USE_UTF8_FILENAME if( _wstat64( OSGDB_STRING_TO_FILENAME(path).c_str(), &stbuf ) == 0 ) #else if( stat64( path.c_str(), &stbuf ) == 0 ) #endif { if( S_ISDIR(stbuf.st_mode)) return true; else { OSG_DEBUG << "osgDB::makeDirectory(): " << path << " already exists and is not a directory!" << std::endl; return false; } } std::string dir = path; std::stack paths; while( true ) { if( dir.empty() ) break; #ifdef OSG_USE_UTF8_FILENAME if( _wstat64( OSGDB_STRING_TO_FILENAME(dir).c_str(), &stbuf ) < 0 ) #else if( stat64( dir.c_str(), &stbuf ) < 0 ) #endif { switch( errno ) { case ENOENT: case ENOTDIR: paths.push( dir ); break; default: OSG_DEBUG << "osgDB::makeDirectory(): " << strerror(errno) << std::endl; return false; } } dir = getFilePath(std::string(dir)); } while( !paths.empty() ) { std::string dir = paths.top(); #if defined(WIN32) //catch drive name if (dir.size() == 2 && dir.c_str()[1] == ':') { paths.pop(); continue; } #endif #ifdef OSG_USE_UTF8_FILENAME if ( _wmkdir(OSGDB_STRING_TO_FILENAME(dir).c_str())< 0 ) #else if( mkdir( dir.c_str(), 0755 )< 0 ) #endif { // Only return an error if the directory actually doesn't exist. It's possible that the directory was created // by another thread or process if (!osgDB::fileExists(dir)) { OSG_DEBUG << "osgDB::makeDirectory(): " << strerror(errno) << std::endl; return false; } } paths.pop(); } return true; } bool osgDB::makeDirectoryForFile( const std::string &path ) { return makeDirectory( getFilePath( path )); } std::string osgDB::getCurrentWorkingDirectory( void ) { // MAX_PATH/cwd inspired by unzip.cpp #ifndef MAX_PATH #define MAX_PATH 1024 #endif TCHAR rootdir[MAX_PATH]; if(getcwd(rootdir,MAX_PATH-1)) { return(rootdir); } return(""); }// osgDB::getCurrentWorkingDirectory bool osgDB::setCurrentWorkingDirectory( const std::string &newCurrentWorkingDirectory ) { if (newCurrentWorkingDirectory.empty()) { OSG_DEBUG << "osgDB::setCurrentWorkingDirectory(): called with empty string." << std::endl; return false; } #ifdef OSG_USE_UTF8_FILENAME return _wchdir( OSGDB_STRING_TO_FILENAME(newCurrentWorkingDirectory).c_str()) == 0; #else return chdir( newCurrentWorkingDirectory.c_str()) == 0; #endif return true; } // osgDB::setCurrentWorkingDirectory void osgDB::convertStringPathIntoFilePathList(const std::string& paths,FilePathList& filepath) { #if defined(WIN32) && !defined(__CYGWIN__) char delimitor = ';'; #else char delimitor = ':'; #endif if (!paths.empty()) { std::string::size_type start = 0; std::string::size_type end; while ((end = paths.find_first_of(delimitor,start))!=std::string::npos) { filepath.push_back(std::string(paths,start,end-start)); start = end+1; } std::string lastPath(paths,start,std::string::npos); if (!lastPath.empty()) filepath.push_back(lastPath); } } bool osgDB::fileExists(const std::string& filename) { #ifdef OSG_USE_UTF8_FILENAME return _waccess( OSGDB_STRING_TO_FILENAME(filename).c_str(), F_OK ) == 0; #else return access( filename.c_str(), F_OK ) == 0; #endif } osgDB::FileType osgDB::fileType(const std::string& filename) { struct stat64 fileStat; #ifdef OSG_USE_UTF8_FILENAME if ( _wstat64(OSGDB_STRING_TO_FILENAME(filename).c_str(), &fileStat) != 0 ) #else if ( stat64(filename.c_str(), &fileStat) != 0 ) #endif { return FILE_NOT_FOUND; } // end if if ( fileStat.st_mode & S_IFDIR ) return DIRECTORY; else if ( fileStat.st_mode & S_IFREG ) return REGULAR_FILE; return FILE_NOT_FOUND; } std::string osgDB::findFileInPath(const std::string& filename, const FilePathList& filepath,CaseSensitivity caseSensitivity) { if (filename.empty()) return filename; if (!isFileNameNativeStyle(filename)) return findFileInPath(convertFileNameToNativeStyle(filename), filepath, caseSensitivity); for(FilePathList::const_iterator itr=filepath.begin(); itr!=filepath.end(); ++itr) { OSG_DEBUG << "itr='" <<*itr<< "'\n"; std::string path = itr->empty() ? filename : concatPaths(*itr, filename); path = getRealPath(path); OSG_DEBUG << "FindFileInPath() : trying " << path << " ...\n"; if(fileExists(path)) { OSG_DEBUG << "FindFileInPath() : USING " << path << "\n"; return path; } #ifndef WIN32 // windows already case insensitive so no need to retry.. else if (caseSensitivity==CASE_INSENSITIVE) { std::string foundfile = findFileInDirectory(filename,*itr,CASE_INSENSITIVE); if (!foundfile.empty()) return foundfile; } #endif } return std::string(); } std::string osgDB::findDataFile(const std::string& filename,CaseSensitivity caseSensitivity) { return findDataFile(filename,static_cast(0),caseSensitivity); } OSGDB_EXPORT std::string osgDB::findDataFile(const std::string& filename,const Options* options, CaseSensitivity caseSensitivity) { return Registry::instance()->findDataFile(filename, options, caseSensitivity); } std::string osgDB::findLibraryFile(const std::string& filename,CaseSensitivity caseSensitivity) { return Registry::instance()->findLibraryFile(filename, osgDB::Registry::instance()->getOptions(), caseSensitivity); } std::string osgDB::findFileInDirectory(const std::string& fileName,const std::string& dirName,CaseSensitivity caseSensitivity) { bool needFollowingBackslash = false; bool needDirectoryName = true; osgDB::DirectoryContents dc; std::string realDirName = dirName; std::string realFileName = fileName; // Skip case-insensitive recursion if on Windows #ifdef WIN32 bool win32 = true; #else bool win32 = false; #endif // If the fileName contains extra path information, make that part of the // directory name instead if (fileName != getSimpleFileName(fileName)) { // See if we need to add a slash between the directory and file if (realDirName.empty()) { realDirName = getFilePath(fileName); } else if (realDirName=="." || realDirName=="./" || realDirName==".\\") { realDirName = "./" + getFilePath(fileName); } else { char lastChar = dirName[dirName.size()-1]; if ((lastChar == '/') || (lastChar == '\\')) realDirName = dirName + getFilePath(fileName); else realDirName = dirName + "/" + getFilePath(fileName); } // Simplify the file name realFileName = getSimpleFileName(fileName); } OSG_DEBUG << "findFileInDirectory() : looking for " << realFileName << " in " << realDirName << "...\n"; if (realDirName.empty()) { dc = osgDB::getDirectoryContents("."); needFollowingBackslash = false; needDirectoryName = false; } else if (realDirName=="." || realDirName=="./" || realDirName==".\\") { dc = osgDB::getDirectoryContents("."); needFollowingBackslash = false; needDirectoryName = false; } else if (realDirName=="/") { dc = osgDB::getDirectoryContents("/"); needFollowingBackslash = false; needDirectoryName = true; } else { // See if we're working in case insensitive mode, and that we're not // using Windows (the recursive search is not needed in these // cases) if ((caseSensitivity == CASE_INSENSITIVE) && (!win32)) { // Split the last path element from the directory name std::string parentPath = getFilePath(realDirName); std::string lastElement = getSimpleFileName(realDirName); // See if we're already at the top level of the filesystem if ((parentPath.empty()) && (!lastElement.empty())) { std::string directoryStringToUse = (realDirName[0]=='/' || realDirName[0]=='\\') ? std::string("/") : std::string("."); // Search for the first path element (ignoring case) in // the top-level directory realDirName = findFileInDirectory(lastElement, directoryStringToUse, CASE_INSENSITIVE); dc = osgDB::getDirectoryContents(realDirName); needFollowingBackslash = true; needDirectoryName = true; } else { // Recursively search for the last path element (ignoring case) // in the parent path realDirName = findFileInDirectory(lastElement, parentPath, CASE_INSENSITIVE); dc = osgDB::getDirectoryContents(realDirName); char lastChar = realDirName[realDirName.size()-1]; if (lastChar=='/') needFollowingBackslash = false; else if (lastChar=='\\') needFollowingBackslash = false; else needFollowingBackslash = true; needDirectoryName = true; } } else { // No need for recursive search if we're doing an exact comparison dc = osgDB::getDirectoryContents(realDirName); char lastChar = realDirName[realDirName.size()-1]; if (lastChar=='/') needFollowingBackslash = false; else if (lastChar=='\\') needFollowingBackslash = false; else needFollowingBackslash = true; needDirectoryName = true; } } for(osgDB::DirectoryContents::iterator itr=dc.begin(); itr!=dc.end(); ++itr) { if ((caseSensitivity==CASE_INSENSITIVE && osgDB::equalCaseInsensitive(realFileName,*itr)) || (realFileName==*itr)) { if (!needDirectoryName) return *itr; else if (needFollowingBackslash) return realDirName+'/'+*itr; else return realDirName+*itr; } } return ""; } static void appendInstallationLibraryFilePaths(osgDB::FilePathList& filepath) { #ifdef OSG_DEFAULT_LIBRARY_PATH // Append the install prefix path to the library search path if configured filepath.push_back(OSG_DEFAULT_LIBRARY_PATH); #endif } #if defined(WIN32) && !defined(__CYGWIN__) #include #include osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName) { osgDB::DirectoryContents contents; OSGDB_WINDOWS_FUNCT(WIN32_FIND_DATA) data; HANDLE handle = OSGDB_WINDOWS_FUNCT(FindFirstFile)((OSGDB_STRING_TO_FILENAME(dirName) + OSGDB_FILENAME_TEXT("\\*")).c_str(), &data); if (handle != INVALID_HANDLE_VALUE) { do { contents.push_back(OSGDB_FILENAME_TO_STRING(data.cFileName)); } while (OSGDB_WINDOWS_FUNCT(FindNextFile)(handle, &data) != 0); FindClose(handle); } return contents; } #else #include osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName) { osgDB::DirectoryContents contents; DIR *handle = opendir(dirName.c_str()); if (handle) { dirent *rc; while((rc = readdir(handle))!=NULL) { contents.push_back(rc->d_name); } closedir(handle); } return contents; } #endif // unix getDirectoryContexts osgDB::DirectoryContents osgDB::getSortedDirectoryContents(const std::string& dirName) { osgDB::DirectoryContents filenames = osgDB::getDirectoryContents(dirName); std::sort(filenames.begin(), filenames.end(), osgDB::FileNameComparator()); return filenames; } osgDB::DirectoryContents osgDB::expandWildcardsInFilename(const std::string& filename) { osgDB::DirectoryContents contents; std::string dir = osgDB::getFilePath(filename); std::string filenameOnly = dir.empty() ? filename : filename.substr(dir.length()+1, std::string::npos); std::string left = filenameOnly.substr(0, filenameOnly.find('*')); std::string right = filenameOnly.substr(filenameOnly.find('*')+1, std::string::npos); if (dir.empty()) dir = osgDB::getCurrentWorkingDirectory(); osgDB::DirectoryContents dirContents = osgDB::getDirectoryContents(dir); for (unsigned int i = 0; i < dirContents.size(); ++i) { std::string filenameInDir = dirContents[i]; if (filenameInDir == "." || filenameInDir == "..") { continue; } if ((filenameInDir.find(left) == 0 || left.empty()) && (filenameInDir.find(right) == filenameInDir.length() - right.length() || right.empty())) { contents.push_back( dir + osgDB::getNativePathSeparator() + filenameInDir ); } } return contents; } osgDB::FileOpResult::Value osgDB::copyFile(const std::string & source, const std::string & destination) { if (source.empty() || destination.empty()) { OSG_INFO << "copyFile(): Empty file name." << std::endl; return FileOpResult::BAD_ARGUMENT; } // Check if source and destination are the same if (source == destination || osgDB::getRealPath(source) == osgDB::getRealPath(destination)) { OSG_INFO << "copyFile(): Source and destination point to the same file: source=" << source << ", destination=" << destination << std::endl; return FileOpResult::SOURCE_EQUALS_DESTINATION; } // Check if source file exists if (!osgDB::fileExists(source)) { OSG_INFO << "copyFile(): Source file does not exist: " << source << std::endl; return FileOpResult::SOURCE_MISSING; } // Open source file osgDB::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); if (!fin) { OSG_NOTICE << "copyFile(): Can't read source file: " << source << std::endl; return FileOpResult::SOURCE_NOT_OPENED; // Return success since it's not an output error. } // Ensure the directory exists or else the FBX SDK will fail if (!osgDB::makeDirectoryForFile(destination)) { OSG_INFO << "Can't create directory for file '" << destination << "'. Copy may fail creating the file." << std::endl; } // Open destination file osgDB::ofstream fout(destination.c_str(), std::ios::out | std::ios::binary | std::ios::trunc); if (!fout) { OSG_NOTICE << "copyFile(): Can't write destination file: " << destination << std::endl; return FileOpResult::DESTINATION_NOT_OPENED; } // Copy file const unsigned int BUFFER_SIZE = 10240; osgDB::ifstream::char_type buffer[BUFFER_SIZE]; for(; fin.good() && fout.good() && !fin.eof(); ) { fin.read(buffer, BUFFER_SIZE); fout.write(buffer, fin.gcount()); } if (!fout.good()) { OSG_NOTICE << "copyFile(): Error writing destination file: " << destination << std::endl; return FileOpResult::WRITE_ERROR; } if (!fin.eof()) { OSG_NOTICE << "copyFile(): Error reading source file: " << source << std::endl; return FileOpResult::READ_ERROR; } return FileOpResult::OK; } bool osgDB::containsCurrentWorkingDirectoryReference(const FilePathList& paths) { const std::string cwd("."); for(FilePathList::const_iterator itr = paths.begin(); itr != paths.end(); ++itr) { if (itr->empty()) return true; if (*itr==cwd) return true; } return false; } ///////////////////////////////////////////////////////////////////////////////////////////////// // // Implementation of appendPlatformSpecificLibraryFilePaths(..) // #ifdef __sgi void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { convertStringPathIntoFilePathList("/usr/lib32/:/usr/local/lib32/",filepath); // bloody mess see rld(1) man page char* ptr; #if (_MIPS_SIM == _MIPS_SIM_ABI32) if( (ptr = getenv( "LD_LIBRARY_PATH" ))) { convertStringPathIntoFilePathList(ptr,filepath); } #elif (_MIPS_SIM == _MIPS_SIM_NABI32) if( !(ptr = getenv( "LD_LIBRARYN32_PATH" ))) ptr = getenv( "LD_LIBRARY_PATH" ); if( ptr ) { convertStringPathIntoFilePathList(ptr,filepath); } #elif (_MIPS_SIM == _MIPS_SIM_ABI64) if( !(ptr = getenv( "LD_LIBRARY64_PATH" ))) ptr = getenv( "LD_LIBRARY_PATH" ); if( ptr ) { convertStringPathIntoFilePathList(ptr,filepath); } #endif appendInstallationLibraryFilePaths(filepath); } #elif defined(__CYGWIN__) void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { char* ptr; if ((ptr = getenv( "PATH" ))) { convertStringPathIntoFilePathList(ptr,filepath); } appendInstallationLibraryFilePaths(filepath); convertStringPathIntoFilePathList("/usr/bin/:/usr/local/bin/",filepath); } #elif defined(WIN32) void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { // See http://msdn2.microsoft.com/en-us/library/ms682586.aspx // Safe DLL search mode changes the DLL search order to search for // DLLs in the current directory after the system directories, instead // of right after the application's directory. According to the article // linked above, on Windows XP and Windows 2000, Safe DLL search mode // is disabled by default. However, it is a good idea to enable it. We // will search as if it was enabled. // So if SafeDllSearchMode is enabled, the search order is as follows: // 1. The directory from which the application loaded. DWORD retval = 0; const DWORD size = MAX_PATH; filenamechar path[size]; retval = OSGDB_WINDOWS_FUNCT(GetModuleFileName)(NULL, path, size); if (retval != 0 && retval < size) { filenamestring pathstr(path); filenamestring executableDir(pathstr, 0, pathstr.find_last_of(OSGDB_FILENAME_TEXT("\\/"))); convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(executableDir), filepath); } else { OSG_WARN << "Could not get application directory " "using Win32 API. It will not be searched." << std::endl; } // 2. The directory that the dll that contains this function is in. // For static builds, this will be the executable directory. #if defined(_MSC_VER) // Requires use of the GetModuleHandleEx() function which is available only on Windows XP or higher. // In order to allow execution on older versions, we load the function dynamically from the library and // use it only if it's available. OSGDB_WINDOWS_FUNCT(PGET_MODULE_HANDLE_EX) pGetModuleHandleEx = reinterpret_cast (GetProcAddress( GetModuleHandleA("kernel32.dll"), OSGDB_WINDOWS_FUNCT_STRING(GetModuleHandleEx))); if( pGetModuleHandleEx ) { HMODULE thisModule = 0; static filenamechar static_variable = 0; // Variable that is located in DLL address space. if( pGetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, &static_variable, &thisModule) ) { retval = OSGDB_WINDOWS_FUNCT(GetModuleFileName)(thisModule, path, size); if (retval != 0 && retval < size) { filenamestring pathstr(path); filenamestring dllDir(pathstr, 0, pathstr.find_last_of(OSGDB_FILENAME_TEXT("\\/"))); convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(dllDir), filepath); } else { OSG_WARN << "Could not get dll directory " "using Win32 API. It will not be searched." << std::endl; } FreeLibrary(thisModule); } else { OSG_WARN << "Could not get dll module handle " "using Win32 API. Dll directory will not be searched." << std::endl; } } #endif // 3. The system directory. Use the GetSystemDirectory function to // get the path of this directory. filenamechar systemDir[(UINT)size]; retval = OSGDB_WINDOWS_FUNCT(GetSystemDirectory)(systemDir, (UINT)size); if (retval != 0 && retval < size) { convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(systemDir), filepath); } else { OSG_WARN << "Could not get system directory using " "Win32 API, using default directory." << std::endl; convertStringPathIntoFilePathList("C:\\Windows\\System32", filepath); } // 4. The 16-bit system directory. There is no function that obtains // the path of this directory, but it is searched. // 5. The Windows directory. Use the GetWindowsDirectory function to // get the path of this directory. filenamechar windowsDir[(UINT)size]; retval = OSGDB_WINDOWS_FUNCT(GetWindowsDirectory)(windowsDir, (UINT)size); if (retval != 0 && retval < size) { convertStringPathIntoFilePathList(std::string(OSGDB_FILENAME_TO_STRING(windowsDir)) + "\\System", filepath); convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(windowsDir), filepath); } else { OSG_WARN << "Could not get Windows directory using " "Win32 API, using default directory." << std::endl; convertStringPathIntoFilePathList("C:\\Windows", filepath); convertStringPathIntoFilePathList("C:\\Windows\\System", filepath); } // 6. The current directory. convertStringPathIntoFilePathList(".", filepath); // 7. The directories that are listed in the PATH environment // variable. Note that this does not include the per-application // path specified by the App Paths registry key. filenamechar* ptr; #ifdef OSG_USE_UTF8_FILENAME if ((ptr = _wgetenv(OSGDB_FILENAME_TEXT("PATH")))) #else if ((ptr = getenv("PATH"))) #endif { // Note that on any sane Windows system, some of the paths above // will also be on the PATH (the values gotten in systemDir and // windowsDir), but the DLL search goes sequentially and stops // when a DLL is found, so I see no point in removing duplicates. convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(ptr), filepath); } appendInstallationLibraryFilePaths(filepath); } #elif defined(__APPLE__) #if (TARGET_OS_IPHONE) || (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) #define COMPILE_COCOA_VERSION #else #define COMPILE_CARBON_VERSION #endif // WARNING: Cocoa version is currently untested. #ifdef COMPILE_COCOA_VERSION #include #endif #ifdef COMPILE_CARBON_VERSION #include #include #include #endif #include // These functions are local to FileUtils.cpp and not exposed to the API // returns the path string except for numToShorten directories stripped off the end std::string GetShortenedPath(std::string path, int numToShorten) { unsigned int i = path.length() - 1; if(path[i] == '/') i--; while(i > 1 && numToShorten) { if(path[i] == '/') numToShorten--; i--; } return path.substr(0,i + 1); } // returns an absolute (POSIX on MacOS X) path from a CFURLRef std::string GetPathFromCFURLRef(CFURLRef urlRef) { char buffer[1024]; std::string path; if(CFURLGetFileSystemRepresentation(urlRef, true, (UInt8*)buffer, 1024)) path = std::string(buffer); return path; } // returns the absolute path to the main bundle std::string GetApplicationBundlePath(CFBundleRef mainBundle) { std::string path; CFURLRef urlRef = CFBundleCopyBundleURL(mainBundle); if(urlRef) { path = GetPathFromCFURLRef(urlRef); CFRelease(urlRef); // docs say we are responsible for releasing CFURLRef } return path; } std::string GetApplicationParentPath(CFBundleRef mainBundle) { return GetShortenedPath(GetApplicationBundlePath(mainBundle), 1); } std::string GetApplicationPluginsPath(CFBundleRef mainBundle) { std::string path; CFURLRef urlRef = CFBundleCopyBuiltInPlugInsURL(mainBundle); if(urlRef) { path = GetPathFromCFURLRef(urlRef); CFRelease(urlRef); } return path; } std::string GetApplicationResourcesPath(CFBundleRef mainBundle) { std::string path; CFURLRef urlRef = CFBundleCopyResourcesDirectoryURL(mainBundle); if(urlRef) { path = GetPathFromCFURLRef(urlRef); CFRelease(urlRef); } return path; } // The Cocoa version is about 10 lines of code. // The Carbon version is noticeably longer. // Unfortunately, the Cocoa version requires -lobjc to be // linked in when creating an executable. // Rumor is that this will be done autmatically in gcc 3.5/Tiger, // but for now, this will cause a lot of headaches for people // who aren't familiar with this concept, so the Carbon version // is preferable. // But for the curious, both implementations are here. // Note that if the Cocoa version is used, the file should be // renamed to use the .mm extension to denote Objective-C++. // And of course, you will need to link against Cocoa // Update: There is a bug in the Cocoa version. Advanced users can remap // their systems so these paths go somewhere else. The Carbon calls // will catch this, but the hardcoded Cocoa code below will not. #ifdef COMPILE_COCOA_VERSION // OS X has preferred locations for where PlugIns should be located. // This function will set this as the order to search: // YourProgram.app/Contents/PlugIns // ~/Library/Application Support/OpenSceneGraph/PlugIns // /Library/Application Support/OpenSceneGraph/PlugIns // /Network/Library/Application Support/OpenSceneGraph/PlugIns // // As a side effect of this function, if the application is not a // bundle, the first place searched becomes // YourProgram/PlugIns // // In principle, these other directories should be searched: // ~/Library/Application Support/YourProgram/PlugIns // /Library/Application Support/YourProgram/PlugIns // /Network/Library/Application Support/TheProgram/PlugIns // But I'm not going to worry about it for now because the // bundle's PlugIns directory is supposed to be the preferred // place for this anyway. // // Another directory that might be worth considering is // the directory the program resides in, // but I'm worried about multiplatform distribution. // Because .so is used by other platforms like Linux, we // could end up loading the wrong binary. // I'm not sure how robust the current code is for this case. // Assuming the program doesn't crash, will OSG move on to the // next search directory, or just give up? void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { char* ptr; if ((ptr = getenv( "DYLD_LIBRARY_PATH" )) ) { convertStringPathIntoFilePathList(ptr, filepath); } appendInstallationLibraryFilePaths(filepath); // Since this is currently the only Objective-C code in the // library, we need an autoreleasepool for obj-c memory management. // If more Obj-C is added, we might move this pool to another // location so it can be shared. Pools seem to be stackable, // so I don't think there will be a problem if multiple pools // exist at a time. NSAutoreleasePool* mypool = [[NSAutoreleasePool alloc] init]; NSString* myBundlePlugInPath; // This will grab the "official" bundle plug in path. // It will be YourProgram.app/Contents/PlugIns (for App bundles) // or YourProgram/PlugIns (for Unix executables) myBundlePlugInPath = [[NSBundle mainBundle] builtInPlugInsPath]; // Since Obj-C and C++ objects don't understand each other, // the Obj-C strings must be converted down to C strings so // C++ can make them into C++ strings. filepath.push_back( [myBundlePlugInPath UTF8String] ); // add all application-support-folders NSArray *systemSearchPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSAllDomainsMask, YES); NSFileManager *fileManager = [NSFileManager defaultManager]; for (NSString *systemPath in systemSearchPaths) { NSString *systemPluginsPath = [systemPath stringByAppendingPathComponent:@"OpenSceneGraph/PlugIns"]; if ([fileManager fileExistsAtPath:systemPluginsPath]) { filepath.push_back( [systemPluginsPath UTF8String] ); } } // Clean up the autorelease pool [mypool release]; } #elif defined(COMPILE_CARBON_VERSION) // OS X has preferred locations for where PlugIns should be located. // This function will set this as the order to search: // YourProgram.app/Contents/PlugIns // ~/Library/Application Support/OpenSceneGraph/PlugIns // /Library/Application Support/OpenSceneGraph/PlugIns // /Network/Library/Application Support/OpenSceneGraph/PlugIns // // In principle, these other directories should be searched: // ~/Library/Application Support/YourProgram/PlugIns // /Library/Application Support/YourProgram/PlugIns // /Network/Library/Application Support/TheProgram/PlugIns // But I'm not going to worry about it for now because the // bundle's PlugIns directory is supposed to be the preferred // place for this anyway. // // Another directory that might be worth considering is // the directory the program resides in, // but I'm worried about multiplatform distribution. // Because .so is used by other platforms like Linux, we // could end up loading the wrong binary. // I'm not sure how robust the current code is for this case. // Assuming the program doesn't crash, will OSG move on to the // next search directory, or just give up? void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { char* ptr; if ((ptr = getenv( "DYLD_LIBRARY_PATH" )) ) { convertStringPathIntoFilePathList(ptr, filepath); } appendInstallationLibraryFilePaths(filepath); const std::string OSG_PLUGIN_PATH("/OpenSceneGraph/PlugIns"); CFURLRef url; CFBundleRef myBundle; FSRef f; OSErr errCode; // Start with the Bundle PlugIns directory. // Get the main bundle first. No need to retain or release it since // we are not keeping a reference myBundle = CFBundleGetMainBundle(); if(myBundle != NULL) { // CFBundleGetMainBundle will return a bundle ref even if // the application isn't part of a bundle, so we need to check // if the path to the bundle ends in ".app" to see if it is a // proper application bundle. If it is, the plugins path is added std::string bundlePath = GetApplicationBundlePath(myBundle); if( bundlePath.substr(bundlePath.length() - 4, 4) == std::string(".app") ) filepath.push_back(GetApplicationPluginsPath(myBundle)); } else { OSG_NOTIFY( osg::DEBUG_INFO ) << "Couldn't find the Application Bundle" << std::endl; } // Next, check the User's Application Support folder int domains[3] = { kUserDomain, kLocalDomain, kNetworkDomain }; for(unsigned int domain_ndx = 0; domain_ndx < 3; ++domain_ndx) { errCode = FSFindFolder( domains[domain_ndx], kApplicationSupportFolderType, kDontCreateFolder, &f ); if(noErr == errCode) { // Get the URL url = CFURLCreateFromFSRef( 0, &f ); if(url) { filepath.push_back(GetPathFromCFURLRef(url) + OSG_PLUGIN_PATH); CFRelease( url ); } else OSG_NOTIFY( osg::DEBUG_INFO ) << "Couldn't create CFURLRef for application support Path at ndx " << domain_ndx << std::endl; url = NULL; } else { OSG_NOTIFY( osg::DEBUG_INFO ) << "Couldn't find the User's Application Support Path at ndx " << domain_ndx << std::endl; } } } #else void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { char* ptr; if ((ptr = getenv( "DYLD_LIBRARY_PATH" )) ) { convertStringPathIntoFilePathList(ptr, filepath); } appendInstallationLibraryFilePaths(filepath); } #endif #else void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath) { char* ptr; if( (ptr = getenv( "LD_LIBRARY_PATH" )) ) { convertStringPathIntoFilePathList(ptr,filepath); } appendInstallationLibraryFilePaths(filepath); #if defined(__ia64__) || defined(__x86_64__) convertStringPathIntoFilePathList("/usr/lib/:/usr/lib64/:/usr/local/lib/:/usr/local/lib64/",filepath); #else convertStringPathIntoFilePathList("/usr/lib/:/usr/local/lib/",filepath); #endif } #endif #ifdef __APPLE__ void osgDB::appendPlatformSpecificResourceFilePaths(FilePathList& filepath) { // Get the main application bundle CFBundleRef mainBundle = CFBundleGetMainBundle(); if (mainBundle != NULL) { // Get the parent directory and the resources directory std::string bundlePath = GetApplicationBundlePath(mainBundle); std::string resourcesPath = GetApplicationResourcesPath(mainBundle); // check if application is really part of a .app bundle if(bundlePath.substr(bundlePath.length() - 4, 4) == std::string(".app")) { if(resourcesPath != std::string("")) filepath.push_back( resourcesPath ); std::string parentPath = GetShortenedPath(bundlePath, 1); if(parentPath != std::string("")) filepath.push_back( parentPath ); } } else { OSG_NOTIFY( osg::DEBUG_INFO ) << "Couldn't find the Application Bundle." << std::endl; } } #else void osgDB::appendPlatformSpecificResourceFilePaths(FilePathList& /*filepath*/) { } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Archive.cpp0000644000175000017500000000663013151044751022741 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include using namespace osgDB; osgDB::Archive* osgDB::openArchive(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint) { return openArchive(filename, status, indexBlockSizeHint, Registry::instance()->getOptions()); } osgDB::Archive* osgDB::openArchive(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint,Options* options) { // ensure archive extension is in the registry list std::string::size_type dot = filename.find_last_of('.'); if (dot != std::string::npos) { std::string ext = filename.substr(dot+1); Registry::instance()->addArchiveExtension(ext); } ReaderWriter::ReadResult result = osgDB::Registry::instance()->openArchive(filename, status, indexBlockSizeHint, options); return result.takeArchive(); } Archive::Archive() { OSG_INFO<<"Archive::Archive() open"< searchPath.size()) { size_t endSubElement = currentFile.find(searchPath); //we match the whole string in the beginning of the path if(endSubElement == 0) { std::string remainingFile = currentFile.substr(searchPath.size() + 1, std::string::npos); size_t endFileToken = remainingFile.find_first_of('/'); if(endFileToken == std::string::npos) { dirContents.push_back(remainingFile); } } } } return dirContents; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Output.cpp0000644000175000017500000001362513151044751022662 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include using namespace std; using namespace osgDB; static osg::ApplicationUsageProxy Output_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WRITE_OUT_DEFAULT_VALUES", "ON | OFF"); Output::Output() { init(); } Output::Output(const char* name) : osgDB::ofstream(name) { init(); _filename = name; } Output::~Output() { } void Output::init() { _indent = 0; _indentStep = 2; _numIndicesPerLine = 10; _pathNameHint = AS_IS; _outputTextureFiles = false; _textureFileNameNumber = 0; _outputShaderFiles = false; _shaderFileNameNumber = 0; _writeOutDefaultValues = false; const char* env = getenv("OSG_WRITE_OUT_DEFAULT_VALUES"); if (env) { _writeOutDefaultValues = strcmp(env,"ON")==0; } } void Output::setOptions(const Options* options) { _options = options; } void Output::open(const char *name) { init(); osgDB::ofstream::open(name); _filename = name; } // Comment out to avoid compile errors under new compilers, the int mode // is now a replaced by a class to wrap the mode. // This method is not used right now to hopefully nobody will miss it... // Jan 2002. // void Output::open(const char *name,int mode) // { // init(); // ofstream::open(name,mode); // _filename = name; // } Output& Output::indent() { for(int i=0;i<_indent;++i) *this<<' '; return *this; } void Output::moveIn() { _indent += _indentStep; } void Output::moveOut() { _indent -= _indentStep; if (_indent<0) _indent=0; } std::string Output::wrapString(const char* str) { if (!str) return std::string("\"\""); return wrapString(std::string(str)); } std::string Output::wrapString(const std::string& str) { std::string newstring; newstring += '"'; for(unsigned int i=0;igetDeprecatedDotOsgObjectWrapperManager()->writeObject(obj,*this); } void Output::writeBeginObject(const std::string& name) { indent() << name << " {" << std::endl; } void Output::writeEndObject() { indent() << "}" << std::endl; } void Output::writeUseID(const std::string& id) { indent() << "Use " << id << std::endl; } void Output::writeUniqueID(const std::string& id) { indent() << "UniqueID " << id << std::endl; } bool Output::getUniqueIDForObject(const osg::Object* obj,std::string& uniqueID) { UniqueIDToLabelMapping::iterator fitr = _objectToUniqueIDMap.find(obj); if (fitr != _objectToUniqueIDMap.end()) { uniqueID = (*fitr).second; return true; } else return false; } bool Output::createUniqueIDForObject(const osg::Object* obj,std::string& uniqueID) { char str[256]; sprintf(str,"%s_%i",obj->className(),(unsigned int)_objectToUniqueIDMap.size()); uniqueID = str; return true; } bool Output::registerUniqueIDForObject(const osg::Object* obj,std::string& uniqueID) { _objectToUniqueIDMap[obj] = uniqueID; return true; } std::string Output::getFileNameForOutput(const std::string& filename) const { switch(_pathNameHint) { case(FULL_PATH): { // need to think about how best to implement this first... OSG_WARN<<"Warning: Output::getFileNameForOutput() does not support FULL_PATH yet."<< std::endl; return filename; } case(RELATIVE_PATH): { // need to think about how best to implement this as well... OSG_WARN<<"Warning: Output::getFileNameForOutput() does not support RELATIVE_PATH yet."<< std::endl; return filename; } case(FILENAME_ONLY): // this one is straight forward. return getSimpleFileName(filename); case(AS_IS): default: // and this one is even more trivial. return filename; } } std::string Output::getTextureFileNameForOutput() { std::string fileName = osgDB::getNameLessExtension(_filename); if (_textureFileNameNumber>0) { std::ostringstream o; o << '_' << _textureFileNameNumber; fileName += o.str(); } fileName += ".dds"; ++_textureFileNameNumber; return fileName; } std::string Output::getShaderFileNameForOutput() { std::string fileName = osgDB::getNameLessExtension(_filename); if (_shaderFileNameNumber>0) { std::ostringstream o; o << '_' << _shaderFileNameNumber; fileName += o.str(); } fileName += ".glsl"; ++_shaderFileNameNumber; return fileName; } void Output::setExternalFileWritten(const std::string& filename, bool hasBeenWritten) { _externalFileWritten[filename] = hasBeenWritten; } bool Output::getExternalFileWritten(const std::string& filename) const { ExternalFileWrittenMap::const_iterator itr = _externalFileWritten.find(filename); if (itr != _externalFileWritten.end()) return itr->second; return false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/ImagePager.cpp0000644000175000017500000002730613151044751023364 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include using namespace osgDB; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SortFileRequestFunctor // struct ImagePager::SortFileRequestFunctor { bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) const { return (lhs->_timeToMergeBy < rhs->_timeToMergeBy); } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // RequestQueue // void ImagePager::RequestQueue::sort() { std::sort(_requestList.begin(),_requestList.end(),SortFileRequestFunctor()); } unsigned int ImagePager::RequestQueue::size() const { OpenThreads::ScopedLock lock(_requestMutex); return _requestList.size(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ReadQueue // ImagePager::ReadQueue::ReadQueue(ImagePager* pager, const std::string& name): _pager(pager), _name(name) { _block = new osg::RefBlock; } void ImagePager::ReadQueue::clear() { OpenThreads::ScopedLock lock(_requestMutex); for(RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ++citr) { (*citr)->_attachmentPoint = 0; (*citr)->_requestQueue = 0; } _requestList.clear(); updateBlock(); } void ImagePager::ReadQueue::add(ImagePager::ImageRequest* imageRequest) { OpenThreads::ScopedLock lock(_requestMutex); _requestList.push_back(imageRequest); imageRequest->_requestQueue = this; OSG_INFO<<"ImagePager::ReadQueue::add("<_fileName<<"), size()="<<_requestList.size()<& databaseRequest) { OpenThreads::ScopedLock lock(_requestMutex); if (!_requestList.empty()) { sort(); OSG_INFO<<"ImagePager::ReadQueue::takeFirst(..), size()="<<_requestList.size()<_requestQueue = 0; _requestList.erase(_requestList.begin()); updateBlock(); } } ////////////////////////////////////////////////////////////////////////////////////// // // ImageThread // ImagePager::ImageThread::ImageThread(ImagePager* pager, Mode mode, const std::string& name): _done(false), _mode(mode), _pager(pager), _name(name) { } ImagePager::ImageThread::ImageThread(const ImageThread& dt, ImagePager* pager): _done(false), _mode(dt._mode), _pager(pager), _name(dt._name) { } ImagePager::ImageThread::~ImageThread() { } int ImagePager::ImageThread::cancel() { int result = 0; if( isRunning() ) { _done = true; switch(_mode) { case(HANDLE_ALL_REQUESTS): _pager->_readQueue->release(); break; case(HANDLE_NON_HTTP): _pager->_readQueue->release(); break; case(HANDLE_ONLY_HTTP): _pager->_readQueue->release(); break; } // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. // _databasePagerThreadBlock->release(); // then wait for the thread to stop running. join(); // _startThreadCalled = false; } //std::cout<<"ImagePager::cancel() thread stopped running"<getFrameNumber()<<">>>>>>>>>>>>>>>>"<getFrameNumber()); } //else OSG_INFO << "signalBeginFrame >>>>>>>>>>>>>>>>"< read_queue; switch(_mode) { case(HANDLE_ALL_REQUESTS): read_queue = _pager->_readQueue; break; case(HANDLE_NON_HTTP): read_queue = _pager->_readQueue; break; case(HANDLE_ONLY_HTTP): read_queue = _pager->_readQueue; break; } do { read_queue->block(); osg::ref_ptr imageRequest; read_queue->takeFirst(imageRequest); if (imageRequest.valid()) { // OSG_NOTICE<<"doing readImageFile("<_fileName<<") index to assign = "<_attachmentIndex< image = osgDB::readRefImageFile(imageRequest->_fileName, imageRequest->_readOptions.get()); if (image.valid()) { // OSG_NOTICE<<" successful readImageFile("<_fileName<<") index to assign = "<_attachmentIndex<(imageRequest->_attachmentPoint.get()); if (is) { if (imageRequest->_attachmentIndex >= 0) { is->setImage(imageRequest->_attachmentIndex, image.get()); } else { is->addImage(image.get()); } } else { imageRequest->_loadedImage = image; OpenThreads::ScopedLock lock(_pager->_completedQueue->_requestMutex); _pager->_completedQueue->_requestList.push_back(imageRequest); } } } else { OpenThreads::Thread::YieldCurrentThread(); } // go to sleep till our the next time our thread gets scheduled. if (firstTime) { // do a yield to get round a peculiar thread hang when testCancel() is called // in certain circumstances - of which there is no particular pattern. YieldCurrentThread(); firstTime = false; } } while (!testCancel() && !_done); OSG_INFO<<"ImagePager::ImageThread::done()"<setDone(true); } // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. _readQueue->release(); for(ImageThreads::iterator itr = _imageThreads.begin(); itr != _imageThreads.end(); ++itr) { (*itr)->cancel(); } _done = true; _startThreadCalled = false; //std::cout<<"DatabasePager::~DatabasePager() stopped running"<(const_cast(options)); return osgDB::readRefImageFile(fileName, readOptions).release(); } void ImagePager::requestImageFile(const std::string& fileName, osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp* /*framestamp*/, osg::ref_ptr& imageRequest, const osg::Referenced* options) { osgDB::Options* readOptions = dynamic_cast(const_cast(options)); if (!readOptions) { readOptions = Registry::instance()->getOptions(); } bool alreadyAssigned = dynamic_cast(imageRequest.get()) && (imageRequest->referenceCount()>1); if (alreadyAssigned) { // OSG_NOTICE<<"ImagePager::requestImageFile("< request = new ImageRequest; request->_timeToMergeBy = timeToMergeBy; request->_fileName = fileName; request->_attachmentPoint = attachmentPoint; request->_attachmentIndex = attachmentIndex; request->_requestQueue = _readQueue.get(); request->_readOptions = readOptions; imageRequest = request; // OSG_NOTICE<<"ImagePager::requestImageFile("<add(request.get()); if (!_startThreadCalled) { OpenThreads::ScopedLock lock(_run_mutex); if (!_startThreadCalled) { _startThreadCalled = true; _done = false; for(ImageThreads::iterator itr = _imageThreads.begin(); itr != _imageThreads.end(); ++itr) { (*itr)->startThread(); } } } } bool ImagePager::requiresUpdateSceneGraph() const { //OSG_NOTICE<<"ImagePager::requiresUpdateSceneGraph()"<_requestList.empty()); } void ImagePager::updateSceneGraph(const osg::FrameStamp&) { OpenThreads::ScopedLock lock(_completedQueue->_requestMutex); for(RequestQueue::RequestList::iterator itr = _completedQueue->_requestList.begin(); itr != _completedQueue->_requestList.end(); ++itr) { ImageRequest* imageRequest = itr->get(); osg::Texture* texture = dynamic_cast(imageRequest->_attachmentPoint.get()); if (texture) { int attachmentIndex = imageRequest->_attachmentIndex > 0 ? imageRequest->_attachmentIndex : 0; texture->setImage(attachmentIndex, imageRequest->_loadedImage.get()); } else { OSG_NOTICE<<"ImagePager::updateSceneGraph() : error, image request attachment type not handled yet."<_requestList.clear(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/SharedStateManager.cpp0000644000175000017500000002476713151044751025075 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgDB; SharedStateManager::SharedStateManager(unsigned int mode): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { setShareMode(mode); _mutex=0; } void SharedStateManager::setShareMode(unsigned int mode) { _shareMode = mode; _shareTexture[osg::Object::DYNAMIC] = (_shareMode & SHARE_DYNAMIC_TEXTURES)!=0; _shareTexture[osg::Object::STATIC] = (_shareMode & SHARE_STATIC_TEXTURES)!=0; _shareTexture[osg::Object::UNSPECIFIED] = (_shareMode & SHARE_UNSPECIFIED_TEXTURES)!=0; _shareStateSet[osg::Object::DYNAMIC] = (_shareMode & SHARE_DYNAMIC_STATESETS)!=0; _shareStateSet[osg::Object::STATIC] = (_shareMode & SHARE_STATIC_STATESETS)!=0; _shareStateSet[osg::Object::UNSPECIFIED] = (_shareMode & SHARE_UNSPECIFIED_STATESETS)!=0; } //---------------------------------------------------------------- // SharedStateManager::prune //---------------------------------------------------------------- void SharedStateManager::prune() { StateSetSet::iterator sitr; OpenThreads::ScopedLock lock(_listMutex); for(sitr=_sharedStateSetList.begin(); sitr!=_sharedStateSetList.end();) { if ((*sitr)->referenceCount()<=1) _sharedStateSetList.erase(sitr++); else ++sitr; } TextureSet::iterator titr; for(titr=_sharedTextureList.begin(); titr!=_sharedTextureList.end();) { if ((*titr)->referenceCount()<=1) _sharedTextureList.erase(titr++); else ++titr; } } //---------------------------------------------------------------- // SharedStateManager::share //---------------------------------------------------------------- void SharedStateManager::share(osg::Node *node, OpenThreads::Mutex *mt) { // const osg::Timer& timer = *osg::Timer::instance(); // osg::Timer_t start_tick = timer.tick(); _mutex = mt; node->accept(*this); tmpSharedTextureList.clear(); tmpSharedStateSetList.clear(); _mutex = 0; // osg::Timer_t end_tick = timer.tick(); // std::cout << "SHARING TIME = "< namespace osgDB // start of osgDB namespace { osgDB::BaseSerializer::Type getTypeEnumFromPtr(const osg::Object*) { return osgDB::BaseSerializer::RW_OBJECT; } const char* getTypeStringFromPtr(const osg::Object*) { return "OBJECT"; } osgDB::BaseSerializer::Type getTypeEnumFromPtr(const osg::Image*) { return osgDB::BaseSerializer::RW_IMAGE; } const char* getTypeStringFromPtr(const osg::Image*) { return "IMAGE"; } /////////////////////////////////////////////////////////////////// // // PropertyOutputIterator enables the get of class properties // class PropertyOutputIterator : public osgDB::OutputIterator { public: PropertyOutputIterator() { } virtual ~PropertyOutputIterator() {} virtual bool isBinary() const { return true; } template inline void write(T t) { char* ptr = reinterpret_cast(&t); _str.insert(_str.size(), ptr, sizeof(T)); } virtual void writeBool( bool b ) { _str.push_back(static_cast(b?1:0)); } virtual void writeChar( char c ) { _str.push_back(c); } virtual void writeUChar( unsigned char c ) { _str.push_back(static_cast(c)); } virtual void writeShort( short s ) { write(s); } virtual void writeUShort( unsigned short s ) { write(s); } virtual void writeInt( int i ) { write(i); } virtual void writeUInt( unsigned int i ) { write(i); } virtual void writeLong( long l ) { write(l); } virtual void writeULong( unsigned long l ) { write(l); } virtual void writeFloat( float f ) { write(f); } virtual void writeDouble( double d ) { write(d); } virtual void writeString( const std::string& s ) { _str.insert(_str.end(), s.begin(), s.end()); } virtual void writeStream( std::ostream& (*fn)(std::ostream&) ) {} virtual void writeBase( std::ios_base& (*fn)(std::ios_base&) ) {} virtual void writeGLenum( const osgDB::ObjectGLenum& value ) { writeInt(value.get()); } virtual void writeProperty( const osgDB::ObjectProperty& prop ) { _propertyName = prop._name; } virtual void writeMark( const osgDB::ObjectMark& mark ) { _markName = mark._name; } virtual void writeCharArray( const char* s, unsigned int size) { _str.insert(std::string::npos, s, size); } virtual void writeWrappedString( const std::string& str ) { _str.insert(_str.end(), str.begin(), str.end()); } virtual void flush() { _str.clear(); _propertyName.clear(); _markName.clear(); } std::string _str; std::string _propertyName; std::string _markName; }; /////////////////////////////////////////////////////////////////// // // PropertyInputIterator enables the set of class properties // class OSGDB_EXPORT PropertyInputIterator : public osgDB::InputIterator { public: PropertyInputIterator(): _sstream(std::stringstream::binary), _bufferData(0), _currentPtr(0), _bufferSize(0) { setStream(&_sstream); } virtual ~PropertyInputIterator() { if (_bufferData) delete [] _bufferData; setStream(0); } virtual bool isBinary() const { return true; } template void read(T& value) { memcpy(reinterpret_cast(&value), _currentPtr, sizeof(T)); _currentPtr += sizeof(T); } virtual void readBool( bool& b ) { char c; read(c); b = (c!=0); } virtual void readChar( char& c ) { read(c); } virtual void readSChar( signed char& c ) { read(c); } virtual void readUChar( unsigned char& c ) { read(c); } virtual void readShort( short& s ) { read(s); } virtual void readUShort( unsigned short& s ) { read(s); } virtual void readInt( int& i ) { read(i); } virtual void readUInt( unsigned int& i ) { read(i);} virtual void readLong( long& l ) { read(l); } virtual void readULong( unsigned long& l ) { read(l); } virtual void readFloat( float& f ) { read(f); } virtual void readDouble( double& d ) { read(d); } virtual void readString( std::string& s ) { s = std::string(_bufferData, _bufferSize); } virtual void readStream( std::istream& (*fn)(std::istream&) ) {} virtual void readBase( std::ios_base& (*fn)(std::ios_base&) ) {} virtual void readGLenum( ObjectGLenum& value ) { readUInt(value._value); } virtual void readProperty( ObjectProperty& prop ) {} virtual void readMark( ObjectMark& mark ) {} virtual void readCharArray( char* s, unsigned int size ) { if ( size>0 ) _in->read( s, size ); } virtual void readWrappedString( std::string& str ) { readString(str); } virtual bool matchString( const std::string& /*str*/ ) { return false; } template void set(const T& value) { if (_bufferData) delete [] _bufferData; _bufferData = new char[sizeof(T)]; _bufferSize = sizeof(T); _currentPtr = _bufferData; memcpy(_bufferData, reinterpret_cast(&value), sizeof(T)); } void set(const void* ptr, unsigned int valueSize) { if (_bufferData) delete [] _bufferData; _bufferData = new char[valueSize]; _currentPtr = _bufferData; _bufferSize = valueSize; memcpy(_bufferData, reinterpret_cast(ptr), valueSize); } std::stringstream _sstream; char* _bufferData; char* _currentPtr; unsigned int _bufferSize; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ClassInterface class provides a generic mechanism for get/setting class properties using the osgDB serializers // ClassInterface::ClassInterface(): _outputStream(0), _inputStream(0) { _poi = new PropertyOutputIterator; _outputStream.setOutputIterator(_poi); _pii = new PropertyInputIterator; _inputStream.setInputIterator(_pii); // initialize the type maps #define TYPENAME(A) \ _typeToTypeNameMap[osgDB::BaseSerializer::RW_##A] = #A; \ _typeNameToTypeMap[#A] = osgDB::BaseSerializer::RW_##A; TYPENAME(UNDEFINED) TYPENAME(USER) TYPENAME(OBJECT) TYPENAME(IMAGE) TYPENAME(LIST) TYPENAME(BOOL) TYPENAME(CHAR) TYPENAME(UCHAR) TYPENAME(SHORT) TYPENAME(USHORT) TYPENAME(INT) TYPENAME(UINT) TYPENAME(FLOAT) TYPENAME(DOUBLE) TYPENAME(VEC2F) TYPENAME(VEC2D) TYPENAME(VEC3F) TYPENAME(VEC3D) TYPENAME(VEC4F) TYPENAME(VEC4D) TYPENAME(QUAT) TYPENAME(PLANE) TYPENAME(MATRIXF) TYPENAME(MATRIXD) TYPENAME(MATRIX) TYPENAME(BOUNDINGBOXF) TYPENAME(BOUNDINGBOXD) TYPENAME(BOUNDINGSPHEREF) TYPENAME(BOUNDINGSPHERED) TYPENAME(GLENUM) TYPENAME(STRING) TYPENAME(ENUM) TYPENAME(VEC2B) TYPENAME(VEC2UB) TYPENAME(VEC2S) TYPENAME(VEC2US) TYPENAME(VEC2I) TYPENAME(VEC2UI) TYPENAME(VEC3B) TYPENAME(VEC3UB) TYPENAME(VEC3S) TYPENAME(VEC3US) TYPENAME(VEC3I) TYPENAME(VEC3UI) TYPENAME(VEC4B) TYPENAME(VEC4UB) TYPENAME(VEC4S) TYPENAME(VEC4US) TYPENAME(VEC4I) TYPENAME(VEC4UI) TYPENAME(LIST) TYPENAME(VECTOR) TYPENAME(MAP) } bool ClassInterface::areTypesCompatible(osgDB::BaseSerializer::Type lhs, osgDB::BaseSerializer::Type rhs) const { if (lhs==rhs) return true; #ifdef OSG_USE_FLOAT_MATRIX if (lhs==osgDB::BaseSerializer::RW_MATRIX) lhs = osgDB::BaseSerializer::RW_MATRIXF; if (rhs==osgDB::BaseSerializer::RW_MATRIX) rhs = osgDB::BaseSerializer::RW_MATRIXF; #else if (lhs==osgDB::BaseSerializer::RW_MATRIX) lhs = osgDB::BaseSerializer::RW_MATRIXD; if (rhs==osgDB::BaseSerializer::RW_MATRIX) rhs = osgDB::BaseSerializer::RW_MATRIXD; #endif if (lhs==osgDB::BaseSerializer::RW_GLENUM) lhs = osgDB::BaseSerializer::RW_UINT; if (rhs==osgDB::BaseSerializer::RW_GLENUM) rhs = osgDB::BaseSerializer::RW_UINT; if (lhs==osgDB::BaseSerializer::RW_ENUM) lhs = osgDB::BaseSerializer::RW_INT; if (rhs==osgDB::BaseSerializer::RW_ENUM) rhs = osgDB::BaseSerializer::RW_INT; if (lhs==osgDB::BaseSerializer::RW_IMAGE) lhs = osgDB::BaseSerializer::RW_OBJECT; return lhs==rhs; } std::string ClassInterface::getTypeName(osgDB::BaseSerializer::Type type) const { TypeToTypeNameMap::const_iterator itr = _typeToTypeNameMap.find(type); if (itr != _typeToTypeNameMap.end()) return itr->second; else return std::string(); } osgDB::BaseSerializer::Type ClassInterface::getType(const std::string& typeName) const { TypeNameToTypeMap::const_iterator itr = _typeNameToTypeMap.find(typeName); if (itr != _typeNameToTypeMap.end()) return itr->second; else return osgDB::BaseSerializer::RW_UNDEFINED; } osgDB::ObjectWrapper* ClassInterface::getObjectWrapper(const osg::Object* object) const { return osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(object->getCompoundClassName()); } osgDB::BaseSerializer* ClassInterface::getSerializer(const osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type& type) const { osgDB::ObjectWrapper* ow = getObjectWrapper(object); return (ow!=0) ? ow->getSerializer(propertyName, type) : 0; } osg::Object* ClassInterface::createObject(const std::string& compoundClassName) const { osgDB::ObjectWrapper* ow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); if (ow) { osg::Object* object = ow->createInstance(); // OSG_NOTICE<<"ClassInterface::createObject("<createInstance() : 0; } bool ClassInterface::copyPropertyDataFromObject(const osg::Object* object, const std::string& propertyName, void* valuePtr, unsigned int valueSize, osgDB::BaseSerializer::Type valueType) { _poi->flush(); osgDB::BaseSerializer::Type sourceType; osgDB::BaseSerializer* serializer = getSerializer(object, propertyName, sourceType); if (!serializer) return false; if (!areTypesCompatible(sourceType, valueType)) { OSG_NOTICE<<"ClassInterface::copyPropertyDataFromObject() Types are not compatible, valueType = "<(valuePtr); _pii->set(&((*string_ptr)[0]), string_ptr->size()); } else { _pii->set(valuePtr, valueSize); } osgDB::BaseSerializer::Type destinationType; osgDB::BaseSerializer* serializer = getSerializer(object, propertyName, destinationType); if (serializer) { if (areTypesCompatible(valueType, destinationType)) { return serializer->read(_inputStream, *object); } else { OSG_NOTICE<<"ClassInterface::copyPropertyDataToObject() Types are not compatible, valueType = "<get(*object, valuePtr); } else { OSG_NOTICE<<"ClassInterface::copyPropertyObjectFromObject() Types are not compatible, valueType = "<set(*object, const_cast(valuePtr)); } else { OSG_NOTICE<<"ClassInterface::copyPropertyObjectToObject() Types are not compatible, valueType = "<getUserDataContainer(); const osg::Object* userObject = udc ? udc->getUserObject(propertyName) : 0; if (userObject) { const osg::ValueObject* valueObject = dynamic_cast(userObject); if (valueObject) { GetPropertyType gpt; valueObject->get(gpt); type = gpt.type; return gpt.type!=osgDB::BaseSerializer::RW_UNDEFINED; } } return false; } bool ClassInterface::getSupportedProperties(const osg::Object* object, PropertyMap& properties, bool searchAssociates) const { osgDB::ObjectWrapper* ow = getObjectWrapper(object); if (!ow) { return false; } std::string compoundClassName = object->getCompoundClassName(); ObjectPropertyMap::const_iterator wl_itr = _whiteList.find(compoundClassName); if (wl_itr != _whiteList.end()) { properties = wl_itr->second; } ObjectPropertyMap::const_iterator bl_itr = _blackList.find(compoundClassName); if (searchAssociates) { const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { osgDB::ObjectWrapper* associate_wrapper = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(*aitr); if (associate_wrapper) { const osgDB::ObjectWrapper::SerializerList& associate_serializers = associate_wrapper->getSerializerList(); unsigned int i=0; for(osgDB::ObjectWrapper::SerializerList::const_iterator sitr = associate_serializers.begin(); sitr != associate_serializers.end(); ++sitr, ++i) { const std::string& propertyName = (*sitr)->getName(); bool notBlackListed = (bl_itr == _blackList.end()) || (bl_itr->second.count(propertyName)==0); if (notBlackListed) properties[propertyName] = associate_wrapper->getTypeList()[i]; } } } } else { const osgDB::ObjectWrapper::SerializerList& serializers = ow->getSerializerList(); unsigned int i=0; for(osgDB::ObjectWrapper::SerializerList::const_iterator itr = serializers.begin(); itr != serializers.end(); ++itr, ++i) { const std::string& propertyName = (*itr)->getName(); bool notBlackListed = (bl_itr == _blackList.end()) || (bl_itr->second.count(propertyName)==0); if (notBlackListed) properties[propertyName] = ow->getTypeList()[i]; } } return true; } bool ClassInterface::isObjectOfType(const osg::Object* object, const std::string& compoundClassName) const { if (!object) return false; if (object->getCompoundClassName()==compoundClassName) return true; osgDB::ObjectWrapper* ow = getObjectWrapper(object); if (!ow) { return false; } const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { if ((*aitr)==compoundClassName) return true; } return false; } bool ClassInterface::run(void* objectPtr, const std::string& compoundClassName, const std::string& methodName, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const { ObjectWrapper* ow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); if (!ow) return false; const ObjectWrapper::MethodObjectMap& methodObjectMap = ow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); while ((itr!=methodObjectMap.end()) && (itr->first==methodName)) { MethodObject* mo = itr->second.get(); if (mo->run(objectPtr, inputParameters, outputParameters)) return true; ++itr; } const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { osgDB::ObjectWrapper* aow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(*aitr); if (aow) { const ObjectWrapper::MethodObjectMap& methodObjectMap = aow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); while ((itr!=methodObjectMap.end()) && (itr->first==methodName)) { MethodObject* mo = itr->second.get(); if (mo->run(objectPtr, inputParameters, outputParameters)) return true; ++itr; } } } return false; } bool ClassInterface::run(osg::Object* object, const std::string& methodName, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const { return run(object, object->getCompoundClassName(), methodName, inputParameters, outputParameters); } bool ClassInterface::hasMethod(const std::string& compoundClassName, const std::string& methodName) const { ObjectWrapper* ow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(compoundClassName); if (!ow) return false; const ObjectWrapper::MethodObjectMap& methodObjectMap = ow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); if (itr!=methodObjectMap.end()) return true; const osgDB::StringList& associates = ow->getAssociates(); for(osgDB::StringList::const_iterator aitr = associates.begin(); aitr != associates.end(); ++aitr) { osgDB::ObjectWrapper* aow = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper(*aitr); if (aow) { const ObjectWrapper::MethodObjectMap& methodObjectMap = aow->getMethodObjectMap(); ObjectWrapper::MethodObjectMap::const_iterator itr = methodObjectMap.find(methodName); if (itr!=methodObjectMap.end()) return true; } } return false; } bool ClassInterface::hasMethod(const osg::Object* object, const std::string& methodName) const { return hasMethod(object->getCompoundClassName(), methodName); } } // end of osgDB namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/fstream.cpp0000644000175000017500000000341013151044751023012 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include namespace osgDB { #ifdef OSG_USE_UTF8_FILENAME #define OSGDB_CONVERT_UTF8_FILENAME(s) convertUTF8toUTF16(s).c_str() #else #define OSGDB_CONVERT_UTF8_FILENAME(s) s #endif void open(std::fstream &fs, const char* filename,std::ios_base::openmode mode) { fs.open(OSGDB_CONVERT_UTF8_FILENAME(filename), mode); } ifstream::ifstream(){} ifstream::ifstream(const char* filename, std::ios_base::openmode mode) : std::ifstream(OSGDB_CONVERT_UTF8_FILENAME(filename), mode) {} ifstream::~ifstream(){} void ifstream::open(const char* filename, std::ios_base::openmode mode) { std::ifstream::open(OSGDB_CONVERT_UTF8_FILENAME(filename), mode); } ofstream::ofstream(){} ofstream::ofstream(const char* filename, std::ios_base::openmode mode) : std::ofstream(OSGDB_CONVERT_UTF8_FILENAME(filename), mode) {} ofstream::~ofstream(){} void ofstream::open(const char* filename, std::ios_base::openmode mode) { std::ofstream::open(OSGDB_CONVERT_UTF8_FILENAME(filename), mode); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/FileCache.cpp0000644000175000017500000004461413151044751023167 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include using namespace osgDB; //////////////////////////////////////////////////////////////////////////////////////////// // // FileCache // FileCache::FileCache(const std::string& path): osg::Referenced(true), _fileCachePath(path) { OSG_INFO<<"Constructed FileCache : "<readObject(cacheFileName, options); } else { return 0; } } ReaderWriter::WriteResult FileCache::writeObject(const osg::Object& object, const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty()) { std::string path = osgDB::getFilePath(cacheFileName); if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) { OSG_NOTICE<<"Could not create cache directory: "<writeObject(object, cacheFileName, options); if (result.success()) { removeFileFromBlackListed(originalFileName); } return result; } return ReaderWriter::WriteResult::FILE_NOT_HANDLED; } ReaderWriter::ReadResult FileCache::readImage(const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty() && osgDB::fileExists(cacheFileName)) { OSG_INFO<<"FileCache::readImageFromCache("<readImage(cacheFileName, options); } else { return 0; } } ReaderWriter::WriteResult FileCache::writeImage(const osg::Image& image, const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty()) { std::string path = osgDB::getFilePath(cacheFileName); if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) { OSG_NOTICE<<"Could not create cache directory: "<writeImage(image, cacheFileName, options); if (result.success()) { removeFileFromBlackListed(originalFileName); } return result; } return ReaderWriter::WriteResult::FILE_NOT_HANDLED; } ReaderWriter::ReadResult FileCache::readHeightField(const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty() && osgDB::fileExists(cacheFileName)) { OSG_INFO<<"FileCache::readHeightFieldFromCache("<readHeightField(cacheFileName, options); } else { return 0; } } ReaderWriter::WriteResult FileCache::writeHeightField(const osg::HeightField& hf, const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty()) { std::string path = osgDB::getFilePath(cacheFileName); if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) { OSG_NOTICE<<"Could not create cache directory: "<writeHeightField(hf, cacheFileName, options); if (result.success()) { removeFileFromBlackListed(originalFileName); } return result; } return ReaderWriter::WriteResult::FILE_NOT_HANDLED; } ReaderWriter::ReadResult FileCache::readNode(const std::string& originalFileName, const osgDB::Options* options, bool buildKdTreeIfRequired) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty() && osgDB::fileExists(cacheFileName)) { OSG_INFO<<"FileCache::readNodeFromCache("<readNode(cacheFileName, options, buildKdTreeIfRequired); } else { return 0; } } ReaderWriter::WriteResult FileCache::writeNode(const osg::Node& node, const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty()) { std::string path = osgDB::getFilePath(cacheFileName); if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) { OSG_NOTICE<<"Could not create cache directory: "<writeNode(node, cacheFileName, options); if (result.success()) { removeFileFromBlackListed(originalFileName); } return result; } return ReaderWriter::WriteResult::FILE_NOT_HANDLED; } ReaderWriter::ReadResult FileCache::readShader(const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty() && osgDB::fileExists(cacheFileName)) { OSG_INFO<<"FileCache::readShaderFromCache("<readShader(cacheFileName, options); } else { return 0; } } ReaderWriter::WriteResult FileCache::writeShader(const osg::Shader& shader, const std::string& originalFileName, const osgDB::Options* options) const { std::string cacheFileName = createCacheFileName(originalFileName); if (!cacheFileName.empty()) { std::string path = osgDB::getFilePath(cacheFileName); if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) { OSG_NOTICE<<"Could not create cache directory: "<writeShader(shader, cacheFileName, options); if (result.success()) { removeFileFromBlackListed(originalFileName); } return result; } return ReaderWriter::WriteResult::FILE_NOT_HANDLED; } bool FileCache::isCachedFileBlackListed(const std::string& originalFileName) const { for(DatabaseRevisionsList::const_iterator itr = _databaseRevisionsList.begin(); itr != _databaseRevisionsList.end(); ++itr) { if ((*itr)->isFileBlackListed(originalFileName)) return true; } return false; } bool FileCache::removeFileFromBlackListed(const std::string& originalFileName) const { for(DatabaseRevisionsList::const_iterator dr_itr = _databaseRevisionsList.begin(); dr_itr != _databaseRevisionsList.end(); ++dr_itr) { DatabaseRevisions* dr = dr_itr->get(); if (dr->getDatabasePath().length()>=originalFileName.length()) continue; if (originalFileName.compare(0,dr->getDatabasePath().length(), dr->getDatabasePath())!=0) continue; std::string localPath(originalFileName, dr->getDatabasePath().empty() ? 0 : dr->getDatabasePath().length()+1, std::string::npos); for(DatabaseRevisions::DatabaseRevisionList::const_iterator itr = dr->getDatabaseRevisionList().begin(); itr != dr->getDatabaseRevisionList().end(); ++itr) { DatabaseRevision* revision = const_cast(itr->get()); if (revision->getFilesAdded() && revision->getFilesAdded()->removeFile(localPath)) { std::string cacheFileName = revision->getFilesAdded()->getName(); if (containsServerAddress(cacheFileName)) cacheFileName = createCacheFileName(cacheFileName); if (!cacheFileName.empty()) writeObjectFile(*(revision->getFilesAdded()), cacheFileName); } if (revision->getFilesRemoved() && revision->getFilesRemoved()->removeFile(localPath)) { std::string cacheFileName = revision->getFilesRemoved()->getName(); if (containsServerAddress(cacheFileName)) cacheFileName = createCacheFileName(cacheFileName); if (!cacheFileName.empty()) writeObjectFile(*(revision->getFilesRemoved()), cacheFileName); } if (revision->getFilesModified() && revision->getFilesModified()->removeFile(localPath)) { std::string cacheFileName = revision->getFilesModified()->getName(); if (containsServerAddress(cacheFileName)) cacheFileName = createCacheFileName(cacheFileName); if (!cacheFileName.empty()) writeObjectFile(*(revision->getFilesModified()), cacheFileName); } } } return false; } bool FileCache::loadDatabaseRevisionsForFile(const std::string& originalFileName) { OSG_INFO<<"FileCache::loadDatabaseRevisionsForFile("< dr_local; std::string cacheFileName = createCacheFileName(revisionsFileName); // check to see if revion file is already loaded. DatabaseRevisionsList::iterator ritr = _databaseRevisionsList.begin(); for(; ritr != _databaseRevisionsList.end() && !dr_local; ++ritr) { OSG_INFO<<" comparing "<<(*ritr)->getName()<<" to "<getName()==revisionsFileName) { OSG_INFO<<"Already loaded"< object = osgDB::readRefObjectFile(cacheFileName); dr_local = dynamic_cast(object.get()); if (dr_local) { OSG_INFO<<" loaded local revisions File("< object = osgDB::readRefObjectFile(revisionsFileName+".curl"); osg::ref_ptr dr_remote = dynamic_cast(object.get()); if (dr_remote.valid()) { bool needToWriteRevisionsFileToDisk = true; if (dr_local.valid()) { if (dr_local->getDatabaseRevisionList().size()==dr_remote->getDatabaseRevisionList().size()) { unsigned int i; for(i=0; igetDatabaseRevisionList().size(); ++i) { DatabaseRevision* revision_local = dr_local->getDatabaseRevision(i); DatabaseRevision* revision_remote = dr_remote->getDatabaseRevision(i); OSG_INFO<<" Comparing local "<getName()<<" to remote "<getName()<getName()!=revision_remote->getName()) break; } needToWriteRevisionsFileToDisk = (i!=dr_local->getDatabaseRevisionList().size()); OSG_INFO<<"Local and remote revisions are different "< dr = dr_remote.valid() ? dr_remote : dr_local; if (dr.valid()) { OSG_INFO<<" loaded remote revisions File("<getName()<getDatabaseRevisionList().begin(); itr != dr->getDatabaseRevisionList().end(); ++itr) { DatabaseRevision* revision = itr->get(); OSG_INFO<<" now loaded DatabaseRevisions "<getName()<<" FileList contents"<getFilesAdded()) { FileList* fileList = readFileList(osgDB::concatPaths(revision->getDatabasePath(), revision->getFilesAdded()->getName())); if (fileList) { revision->setFilesAdded(fileList); } } if (revision->getFilesRemoved()) { FileList* fileList = readFileList(osgDB::concatPaths(revision->getDatabasePath(), revision->getFilesRemoved()->getName())); if (fileList) { revision->setFilesRemoved(fileList); } } if (revision->getFilesModified()) { FileList* fileList = readFileList(osgDB::concatPaths(revision->getDatabasePath(), revision->getFilesModified()->getName())); if (fileList) { revision->setFilesModified(fileList); } } } return true; } else { OSG_NOTICE<<" failed to read revisions File, object.get()="< fileList; std::string cacheFileListName = createCacheFileName(originalFileName); if (!cacheFileListName.empty() && osgDB::fileExists(cacheFileListName)) { osg::ref_ptr object = osgDB::readRefObjectFile(cacheFileListName); fileList = dynamic_cast(object.get()); if (fileList) OSG_INFO<<" loadeded FileList from local cache "<getName()<(object.get()); if (fileList) { OSG_INFO<<" loadeded FileList from remote system "<getName()<getName()< #include #include #include #include namespace osgDB { /// Counts the number of directories the given relative path goes "up" the current dir, or 0 if not. /// This returns 0 for absolute paths. /// Examples: /// - "../a" goes 1 level up /// - "../../a/b/c/d/e" goes 2 /// - "../a/../b/../.." goes 2 /// - "a/b/../c" goes 0 static unsigned int countNbDirsUp(const std::string & path) { // Algorithm: // - For each path component, count +1 for "..", 0 for ".", and -1 for anything else // - Ignore everything after the last ".." of the path. if (isAbsolutePath(path)) return 0; int result(0), tempResult(0); std::vector pathElems; getPathElements(path, pathElems); for(std::vector::const_iterator it(pathElems.begin()), itEnd(pathElems.end()); it!=itEnd; ++it) { if (*it == "..") { // Count +1, and "validates" temporary result ++tempResult; result = tempResult; } else if (*it != ".") --tempResult; } return result<=0 ? 0 : static_cast(result); } /// Local hash function for a path. /// Does not canonize the given path, but is not confused with mixed separators. static unsigned int pathHash(const std::string & s) { // This is based on the DJB hash algorithm // Note: SDBM Hash initializes at 0 and is // hash = c + (hash << 6) + (hash << 16) - hash; unsigned int hash = 5381; for(std::string::const_iterator it=s.begin(), itEnd=s.end(); it!=itEnd; ++it) { std::string::value_type c = *it; if (c == '\\') c = '/'; // We're processing a path and don't want to be affected by differences in separators hash = ((hash << 5) + hash) + c; } return hash; } //virtual ReaderWriter::WriteResult writeObject(const osg::Object& obj, const std::string& fileName,const Options* options); //virtual ReaderWriter::WriteResult writeImage(const osg::Image& obj, const std::string& fileName,const Options* options); //virtual ReaderWriter::WriteResult writeHeightField(const osg::HeightField& obj, const std::string& fileName,const Options* options); //virtual ReaderWriter::WriteResult writeNode(const osg::Node& obj, const std::string& fileName,const Options* options); //virtual ReaderWriter::WriteResult writeShader(const osg::Shader& obj, const std::string& fileName,const Options* options); enum WriteType { WRITE_TYPE_OBJECT, WRITE_TYPE_IMAGE, WRITE_TYPE_HEIGHT_FIELD, WRITE_TYPE_NODE, WRITE_TYPE_SHADER, MAX_WRITE_TYPE }; /// Default prefixes for unnamed objects. static const char * const FILE_PREFIX[/*MAX_WRITE_TYPE*/] = { "Object_", "Image_", "HF_", "Node_", "Shader_" }; /// Default prefixes for unnamed objects. static const char * const FILE_EXTENSION[/*MAX_WRITE_TYPE*/] = { ".osgb", ".tga", ".osgb", ".osgb", ".glsl" }; //.frag //.vert inline WriteType getType(const osg::Object & obj) { // Is there something faster than a dynamic_cast<>? if (dynamic_cast(&obj)) return WRITE_TYPE_IMAGE; if (dynamic_cast(&obj)) return WRITE_TYPE_HEIGHT_FIELD; if (dynamic_cast(&obj)) return WRITE_TYPE_NODE; if (dynamic_cast(&obj)) return WRITE_TYPE_SHADER; return WRITE_TYPE_OBJECT; } /// Returns the object filename if available, or its name otherwise. inline const std::string & getFileName(const osg::Object & obj, WriteType type) { switch(type) { case WRITE_TYPE_IMAGE: return static_cast(obj).getFileName(); case WRITE_TYPE_SHADER: return static_cast(obj).getFileName(); default: // WRITE_TYPE_OBJECT, WRITE_TYPE_NODE, WRITE_TYPE_HEIGHT_FIELD return obj.getName(); } } inline bool doWrite(const osg::Object & obj, WriteType type, const std::string& fileName, const Options * options) { switch(type) { case WRITE_TYPE_IMAGE: return writeImageFile (static_cast(obj), fileName, options); case WRITE_TYPE_HEIGHT_FIELD: return writeHeightFieldFile(static_cast(obj), fileName, options); case WRITE_TYPE_NODE: return writeNodeFile (static_cast(obj), fileName, options); case WRITE_TYPE_SHADER: return writeShaderFile (static_cast(obj), fileName, options); // WRITE_TYPE_OBJECT default: return writeObjectFile(obj, fileName, options); } } // -------------------------------------------------------------------------------- ExternalFileWriter::ExternalFileWriter(const std::string & srcDirectory, const std::string & destDirectory, bool keepRelativePaths, unsigned int allowUpDirs) : _lastGeneratedObjectIndex(0), _srcDirectory(srcDirectory), _destDirectory(destDirectory), _keepRelativePaths(keepRelativePaths), _allowUpDirs(allowUpDirs) {} ExternalFileWriter::ExternalFileWriter(const std::string & destDirectory) : _lastGeneratedObjectIndex(0), _destDirectory(destDirectory), _keepRelativePaths(false), _allowUpDirs(0) {} bool ExternalFileWriter::write(const osg::Object & obj, const Options * options, std::string * out_absolutePath, std::string * out_relativePath) { ObjectsSet::iterator it( _objects.find(&obj) ); if (it != _objects.end()) { // Object has already been passed to this method if (out_absolutePath) *out_absolutePath = it->second.absolutePath; if (out_relativePath) *out_relativePath = it->second.relativePath; return it->second.written; } // Object is a new entry // Get absolute source path WriteType type( getType(obj) ); std::string originalFileName( getFileName(obj, type) ); std::string absoluteSourcePath; if (_keepRelativePaths && !originalFileName.empty()) // if keepRelativePaths is false, absoluteSourcePath is not used, then we can skip this part { if (isAbsolutePath(originalFileName)) absoluteSourcePath = originalFileName; else absoluteSourcePath = concatPaths(_srcDirectory, originalFileName); absoluteSourcePath = getRealPath(convertFileNameToNativeStyle(absoluteSourcePath)); // getRealPath() here is only used to canonize the path, not to add current directory in front of relative paths, hence the "concatPaths(_srcDirectory, ...)" just above } // Compute destination paths from the source path std::string relativeDestinationPath; std::string absoluteDestinationPath; if (absoluteSourcePath.empty()) { // We have no name. Generate one. generateObjectName(relativeDestinationPath, absoluteDestinationPath, type); } else { // We have a name. if (_keepRelativePaths) { // We'll try to keep images relative path. relativeDestinationPath = getPathRelative(_srcDirectory, absoluteSourcePath); unsigned int nbDirsUp = countNbDirsUp(relativeDestinationPath); // TODO if nbDirsUp>nb dirs in _destDirectory, then issue a warning, and use simple file name if (nbDirsUp > _allowUpDirs) relativeDestinationPath = getSimpleFileName(absoluteSourcePath); } else { // We keep only the simple file name. relativeDestinationPath = getSimpleFileName(absoluteSourcePath); } absoluteDestinationPath = getRealPath(convertFileNameToNativeStyle( concatPaths(_destDirectory, relativeDestinationPath) )); // TODO Check for absolute paths collisions between multiple objects } // Write object bool written(false); if (!makeDirectoryForFile(absoluteDestinationPath)) { OSG_NOTICE << "Can't create directory for file '" << absoluteDestinationPath << "'. May fail creating the image file." << std::endl; } if (!doWrite(obj, type, absoluteDestinationPath, options)) { OSG_WARN << "Can't write file '" << absoluteDestinationPath << "'." << std::endl; } else written = true; // Add entry _objects.insert(ObjectsSet::value_type(&obj, ObjectData(absoluteDestinationPath, relativeDestinationPath, written))); _searchMap.insert(SearchMap::value_type(pathHash(absoluteDestinationPath), &obj)); // Fill output strings if (out_absolutePath) *out_absolutePath = absoluteDestinationPath; if (out_relativePath) *out_relativePath = relativeDestinationPath; return written; } bool ExternalFileWriter::absoluteObjectPathExists(const std::string & path) { // For all paths in the search map having the same hash as 'path', check if paths correspond std::pair bounds( _searchMap.equal_range(pathHash(path)) ); for(SearchMap::iterator it=bounds.first; it!=bounds.second; ++it) { const osg::Object * img( it->second ); if (_objects[img].absolutePath == path) return true; } return false; } void ExternalFileWriter::generateObjectName(std::string & out_relativePath, std::string & out_absolutePath, int type) { static const ObjectIndex MAX_NUMBER = UINT_MAX-1; // -1 to allow doing +1 without an overflow for (ObjectIndex number=_lastGeneratedObjectIndex+1; number #include #include #include #include using namespace osgDB; // Example compressor copying data to/from stream directly class NullCompressor : public BaseCompressor { public: NullCompressor() {} virtual bool compress( std::ostream& fout, const std::string& src ) { int size = src.size(); fout.write( (char*)&size, INT_SIZE ); fout.write( src.c_str(), src.size() ); return true; } virtual bool decompress( std::istream& fin, std::string& target ) { int size = 0; fin.read( (char*)&size, INT_SIZE ); if ( size ) { target.resize( size ); fin.read( (char*)target.c_str(), size ); } return true; } }; REGISTER_COMPRESSOR( "null", NullCompressor ) #ifdef USE_ZLIB #include #define CHUNK 32768 // ZLib compressor class ZLibCompressor : public BaseCompressor { public: ZLibCompressor() {} virtual bool compress( std::ostream& fout, const std::string& src ) { int ret, flush = Z_FINISH; unsigned have; z_stream strm; unsigned char out[CHUNK]; int level = 6; int stategy = Z_DEFAULT_STRATEGY; /* allocate deflate state */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; ret = deflateInit2( &strm, level, Z_DEFLATED, 15+16, // +16 to use gzip encoding 8, // default stategy ); if ( ret != Z_OK ) return false; strm.avail_in = src.size(); strm.next_in = (Bytef*)( &(*src.begin()) ); /* run deflate() on input until output buffer not full, finish compression if all of source has been read in */ do { strm.avail_out = CHUNK; strm.next_out = out; ret = deflate(&strm, flush); /* no bad return value */ if ( ret == Z_STREAM_ERROR ) { OSG_NOTICE << "Z_STREAM_ERROR" << std::endl; return false; } have = CHUNK - strm.avail_out; if ( have>0 ) fout.write( (const char*)out, have ); if ( fout.fail() ) { (void)deflateEnd( &strm ); return false; } } while ( strm.avail_out==0 ); /* clean up and return */ (void)deflateEnd( &strm ); return true; } virtual bool decompress( std::istream& fin, std::string& target ) { int ret; unsigned have; z_stream strm; unsigned char in[CHUNK]; unsigned char out[CHUNK]; /* allocate inflate state */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit2( &strm, 15 + 32 ); // autodected zlib or gzip header if ( ret!=Z_OK ) { OSG_INFO << "failed to init" << std::endl; return ret!=0; } /* decompress until deflate stream ends or end of file */ do { fin.read( (char *)in, CHUNK ); strm.avail_in = fin.gcount(); if (strm.avail_in==0 ) break; /* run inflate() on input until output buffer not full */ strm.next_in = in; do { strm.avail_out = CHUNK; strm.next_out = out; ret = inflate( &strm, Z_NO_FLUSH ); switch (ret) { case Z_NEED_DICT: case Z_DATA_ERROR: case Z_MEM_ERROR: (void)inflateEnd( &strm ); return false; } have = CHUNK - strm.avail_out; target.append( (char*)out, have ); } while ( strm.avail_out==0 ); /* done when inflate() says it's done */ } while ( ret!=Z_STREAM_END ); /* clean up and return */ (void)inflateEnd( &strm ); return ret==Z_STREAM_END ? true : false; } }; REGISTER_COMPRESSOR( "zlib", ZLibCompressor ) #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/OutputStream.cpp0000644000175000017500000010201013151044751024021 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // Written by Wang Rui, (C) 2010 #include #include #include #include #include #include #include #include #include using namespace osgDB; OutputStream::OutputStream( const osgDB::Options* options ) : _writeImageHint(WRITE_USE_IMAGE_HINT), _useSchemaData(false), _useRobustBinaryFormat(true) { BEGIN_BRACKET.set( "{", +INDENT_VALUE ); END_BRACKET.set( "}", -INDENT_VALUE ); if ( !options ) return; _options = options; if ( options->getPluginStringData("RobustBinaryFormat")=="false" ) _useRobustBinaryFormat = false; if ( options->getPluginStringData("SchemaData")=="true" ) _useSchemaData = true; if ( !options->getPluginStringData("SchemaFile").empty() ) _schemaName = options->getPluginStringData("SchemaFile"); if ( !options->getPluginStringData("Compressor").empty() ) _compressorName = options->getPluginStringData("Compressor"); if ( !options->getPluginStringData("WriteImageHint").empty() ) { std::string hintString = options->getPluginStringData("WriteImageHint"); if ( hintString=="IncludeData" ) _writeImageHint = WRITE_INLINE_DATA; else if ( hintString=="IncludeFile" ) _writeImageHint = WRITE_INLINE_FILE; else if ( hintString=="UseExternal" ) _writeImageHint = WRITE_USE_EXTERNAL; else if ( hintString=="WriteOut" ) _writeImageHint = WRITE_EXTERNAL_FILE; } if ( !options->getPluginStringData("CustomDomains").empty() ) { StringList domains, keyAndValue; split( options->getPluginStringData("CustomDomains"), domains, ';' ); for ( unsigned int i=0; i1 ) _domainVersionMap[keyAndValue.front()] = atoi(keyAndValue.back().c_str()); } } } OutputStream::~OutputStream() { } int OutputStream::getFileVersion( const std::string& d ) const { if ( d.empty() ) return OPENSCENEGRAPH_SOVERSION; VersionMap::const_iterator itr = _domainVersionMap.find(d); return itr==_domainVersionMap.end() ? 0 : itr->second; } OutputStream& OutputStream::operator<<( const osg::Vec2b& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3b& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4b& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2ub& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3ub& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4ub& v ) { *this << v.r() << v.g() << v.b() << v.a(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2s& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3s& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4s& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2us& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3us& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4us& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2f& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3f& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4f& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2d& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3d& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4d& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2i& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3i& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4i& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec2ui& v ) { *this << v.x() << v.y(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec3ui& v ) { *this << v.x() << v.y() << v.z(); return *this; } OutputStream& OutputStream::operator<<( const osg::Vec4ui& v ) { *this << v.x() << v.y() << v.z() << v.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Quat& q ) { *this << q.x() << q.y() << q.z() << q.w(); return *this; } OutputStream& OutputStream::operator<<( const osg::Plane& p ) { *this << (double)p[0] << (double)p[1] << (double)p[2] << (double)p[3]; return *this; } OutputStream& OutputStream::operator<<( const osg::BoundingBoxf& bb) { *this << bb.xMin() << bb.yMin() << bb.zMin() << bb.xMax() << bb.yMax() << bb.zMax(); return *this; } OutputStream& OutputStream::operator<<( const osg::BoundingBoxd& bb) { *this << bb.xMin() << bb.yMin() << bb.zMin() << bb.xMax() << bb.yMax() << bb.zMax(); return *this; } OutputStream& OutputStream::operator<<( const osg::BoundingSpheref& bs) { *this << bs.center().x() << bs.center().y() << bs.center().z() << bs.radius(); return *this; } OutputStream& OutputStream::operator<<( const osg::BoundingSphered& bs) { *this << bs.center().x() << bs.center().y() << bs.center().z() << bs.radius(); return *this; } #if 0 OutputStream& OutputStream::operator<<( const osg::Matrixf& mat ) { *this << PROPERTY("Matrixf")<getType() ) { case osg::Array::ByteArrayType: *this << MAPPEE(ArrayType, ID_BYTE_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::UByteArrayType: *this << MAPPEE(ArrayType, ID_UBYTE_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::ShortArrayType: *this << MAPPEE(ArrayType, ID_SHORT_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::UShortArrayType: *this << MAPPEE(ArrayType, ID_USHORT_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::IntArrayType: *this << MAPPEE(ArrayType, ID_INT_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::UIntArrayType: *this << MAPPEE(ArrayType, ID_UINT_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::FloatArrayType: *this << MAPPEE(ArrayType, ID_FLOAT_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::DoubleArrayType: *this << MAPPEE(ArrayType, ID_DOUBLE_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements(), 4 ); break; case osg::Array::Vec2bArrayType: *this << MAPPEE(ArrayType, ID_VEC2B_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3bArrayType: *this << MAPPEE(ArrayType, ID_VEC3B_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4bArrayType: *this << MAPPEE(ArrayType, ID_VEC4B_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2ubArrayType: *this << MAPPEE(ArrayType, ID_VEC2UB_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3ubArrayType: *this << MAPPEE(ArrayType, ID_VEC3UB_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4ubArrayType: *this << MAPPEE(ArrayType, ID_VEC4UB_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2sArrayType: *this << MAPPEE(ArrayType, ID_VEC2S_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3sArrayType: *this << MAPPEE(ArrayType, ID_VEC3S_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4sArrayType: *this << MAPPEE(ArrayType, ID_VEC4S_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2usArrayType: *this << MAPPEE(ArrayType, ID_VEC2US_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3usArrayType: *this << MAPPEE(ArrayType, ID_VEC3US_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4usArrayType: *this << MAPPEE(ArrayType, ID_VEC4US_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2ArrayType: *this << MAPPEE(ArrayType, ID_VEC2_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3ArrayType: *this << MAPPEE(ArrayType, ID_VEC3_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4ArrayType: *this << MAPPEE(ArrayType, ID_VEC4_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2dArrayType: *this << MAPPEE(ArrayType, ID_VEC2D_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3dArrayType: *this << MAPPEE(ArrayType, ID_VEC3D_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4dArrayType: *this << MAPPEE(ArrayType, ID_VEC4D_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2iArrayType: *this << MAPPEE(ArrayType, ID_VEC2I_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3iArrayType: *this << MAPPEE(ArrayType, ID_VEC3I_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4iArrayType: *this << MAPPEE(ArrayType, ID_VEC4I_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec2uiArrayType: *this << MAPPEE(ArrayType, ID_VEC2UI_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec3uiArrayType: *this << MAPPEE(ArrayType, ID_VEC3UI_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; case osg::Array::Vec4uiArrayType: *this << MAPPEE(ArrayType, ID_VEC4UI_ARRAY); writeArrayImplementation( static_cast(a), a->getNumElements() ); break; default: throwException( "OutputStream::writeArray(): Unsupported array type." ); } } void OutputStream::writePrimitiveSet( const osg::PrimitiveSet* p ) { if ( !p ) return; switch ( p->getType() ) { case osg::PrimitiveSet::DrawArraysPrimitiveType: *this << MAPPEE(PrimitiveType, ID_DRAWARRAYS); { const osg::DrawArrays* da = static_cast(p); *this << MAPPEE(PrimitiveType, da->getMode()) << da->getNumInstances() << da->getFirst() << da->getCount() << std::endl; } break; case osg::PrimitiveSet::DrawArrayLengthsPrimitiveType: *this << MAPPEE(PrimitiveType, ID_DRAWARRAY_LENGTH); { const osg::DrawArrayLengths* dl = static_cast(p); *this << MAPPEE(PrimitiveType, dl->getMode()) << dl->getNumInstances() << dl->getFirst(); writeArrayImplementation( dl, dl->size(), 4 ); } break; case osg::PrimitiveSet::DrawElementsUBytePrimitiveType: *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_UBYTE); { const osg::DrawElementsUByte* de = static_cast(p); *this << MAPPEE(PrimitiveType, de->getMode()) << de->getNumInstances(); writeArrayImplementation( de, de->size(), 4 ); } break; case osg::PrimitiveSet::DrawElementsUShortPrimitiveType: *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_USHORT); { const osg::DrawElementsUShort* de = static_cast(p); *this << MAPPEE(PrimitiveType, de->getMode()) << de->getNumInstances(); writeArrayImplementation( de, de->size(), 4 ); } break; case osg::PrimitiveSet::DrawElementsUIntPrimitiveType: *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_UINT); { const osg::DrawElementsUInt* de = static_cast(p); *this << MAPPEE(PrimitiveType, de->getMode()) << de->getNumInstances(); writeArrayImplementation( de, de->size(), 4 ); } break; default: throwException( "OutputStream::writePrimitiveSet(): Unsupported primitive type." ); } } void OutputStream::writeImage( const osg::Image* img ) { if ( !img ) return; std::string name = img->libraryName(); name += std::string("::") + img->className(); bool newID = false; unsigned int id = findOrCreateObjectID( img, newID ); *this << PROPERTY("ClassName") << name << std::endl; // Write object name *this << PROPERTY("UniqueID") << id << std::endl; // Write image ID if ( getException() ) return; if (newID) { int decision = IMAGE_EXTERNAL; switch ( _writeImageHint ) { case OutputStream::WRITE_INLINE_DATA: decision = IMAGE_INLINE_DATA; break; case OutputStream::WRITE_INLINE_FILE: decision = IMAGE_INLINE_FILE; break; case OutputStream::WRITE_EXTERNAL_FILE: decision = IMAGE_WRITE_OUT; break; case OutputStream::WRITE_USE_EXTERNAL: decision = IMAGE_EXTERNAL; break; default: if ( img->getWriteHint()==osg::Image::EXTERNAL_FILE ) decision = IMAGE_EXTERNAL; else if ( isBinary() ) decision = IMAGE_INLINE_DATA; break; } std::string imageFileName = img->getFileName(); if ( decision==IMAGE_WRITE_OUT || _writeImageHint==WRITE_EXTERNAL_FILE ) { if (imageFileName.empty()) { OSG_NOTICE<<"Empty Image::FileName resetting to image.dds"<getFileName() << std::endl; } } *this << PROPERTY("FileName"); writeWrappedString(imageFileName); *this << std::endl; *this << PROPERTY("WriteHint") << (int)img->getWriteHint(); if ( getException() ) return; *this << decision << std::endl; switch ( decision ) { case IMAGE_INLINE_DATA: if ( isBinary() ) { *this << img->getOrigin(); // _origin *this << img->s() << img->t() << img->r(); // _s & _t & _r *this << img->getInternalTextureFormat(); // _internalTextureFormat *this << img->getPixelFormat(); // _pixelFormat *this << img->getDataType(); // _dataType *this << img->getPacking(); // _packing *this << img->getAllocationMode(); // _allocationMode // _data unsigned int size = img->getTotalSizeInBytesIncludingMipmaps(); writeSize(size); for(osg::Image::DataIterator img_itr(img); img_itr.valid(); ++img_itr) { writeCharArray( (char*)img_itr.data(), img_itr.size() ); } // _mipmapData unsigned int numMipmaps = img->getNumMipmapLevels()-1; writeSize(numMipmaps); int s = img->s(); int t = img->t(); int r = img->r(); unsigned int offset = 0; for (unsigned int i=0; igetPixelFormat(),img->getDataType(),img->getPacking()); offset += size; *this << offset; s >>= 1; t >>= 1; r >>= 1; if (s<1) s=1; if (t<1) t=1; if (r<1) r=1; } } else { // ASCII *this << PROPERTY("Origin") << img->getOrigin() << std::endl; // _origin *this << PROPERTY("Size") << img->s() << img->t() << img->r() << std::endl; // _s & _t & _r *this << PROPERTY("InternalTextureFormat") << img->getInternalTextureFormat() << std::endl; // _internalTextureFormat *this << PROPERTY("PixelFormat") << img->getPixelFormat() << std::endl; // _pixelFormat *this << PROPERTY("DataType") << img->getDataType() << std::endl; // _dataType *this << PROPERTY("Packing") << img->getPacking() << std::endl; // _packing *this << PROPERTY("AllocationMode") << img->getAllocationMode() << std::endl; // _allocationMode // _data *this << PROPERTY("Data") << img->getNumMipmapLevels(); *this << BEGIN_BRACKET << std::endl; Base64encoder e; for(osg::Image::DataIterator img_itr(img); img_itr.valid(); ++img_itr) { std::string encodedData; e.encode((char*)img_itr.data(), img_itr.size(), encodedData); // Each set of data is written into a separate string so we can // distiguish between main data and all mipmap levels, so writing // mipmap size is not required for ASCII mode. writeWrappedString(encodedData); } *this << END_BRACKET << std::endl; } break; case IMAGE_INLINE_FILE: if ( isBinary() ) { std::string fullPath = osgDB::findDataFile( img->getFileName() ); osgDB::ifstream infile( fullPath.c_str(), std::ios::in|std::ios::binary ); if ( infile ) { infile.seekg( 0, std::ios::end ); unsigned int size = infile.tellg(); writeSize(size); if ( size>0 ) { char* data = new char[size]; if ( !data ) { throwException( "OutputStream::writeImage(): Out of memory." ); if ( getException() ) return; } infile.seekg( 0, std::ios::beg ); infile.read( data, size ); writeCharArray( data, size ); delete[] data; } infile.close(); } else { OSG_WARN << "OutputStream::writeImage(): Failed to open image file " << img->getFileName() << std::endl; *this << (unsigned int)0; } } break; case IMAGE_EXTERNAL: break; default: break; } writeObjectFields( img, "osg::Object" ); } // *this << END_BRACKET << std::endl; } void OutputStream::writeObject( const osg::Object* obj ) { if ( !obj ) { *this << std::string("NULL") << std::endl; // Write NULL token. return; } std::string name = obj->libraryName(); name += std::string("::") + obj->className(); bool newID = false; unsigned int id = findOrCreateObjectID( obj, newID ); *this << name << BEGIN_BRACKET << std::endl; // Write object name *this << PROPERTY("UniqueID") << id << std::endl; // Write object ID if ( getException() ) return; if (newID) { writeObjectFields(obj); } *this << END_BRACKET << std::endl; } void OutputStream::writeObjectFields( const osg::Object* obj ) { std::string name = obj->libraryName(); name += std::string("::") + obj->className(); writeObjectFields(obj, name); } void OutputStream::writeObjectFields( const osg::Object* obj, const std::string& name ) { // OSG_NOTICE<<"OutputStream::writeObjectFields("<className()<<", name="<getObjectWrapperManager()->findWrapper( name ); if ( !wrapper ) { OSG_WARN << "OutputStream::writeObject(): Unsupported wrapper class " << name << std::endl; return; } const StringList& associates = wrapper->getAssociates(); for ( StringList::const_iterator itr=associates.begin(); itr!=associates.end(); ++itr ) { const std::string& assocName = *itr; ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName); if ( !assocWrapper ) { OSG_WARN << "OutputStream::writeObject(): Unsupported associated class " << assocName << std::endl; continue; } else if ( _useSchemaData ) { if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() ) { StringList properties; ObjectWrapper::TypeList types; assocWrapper->writeSchema( properties, types ); unsigned int size = osg::minimum( properties.size(), types.size() ); if ( size>0 ) { std::stringstream propertiesStream; for ( unsigned int i=0; igetName() ); assocWrapper->write( *this, *obj ); if ( getException() ) return; _fields.pop_back(); } } void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType type ) { _fields.clear(); _fields.push_back( "Start" ); _out = outIterator; if ( !_out ) throwException( "OutputStream: Null stream specified." ); if ( getException() ) return; if ( isBinary() ) { *this << (unsigned int)type << (unsigned int)OPENSCENEGRAPH_SOVERSION; bool useCompressSource = false; unsigned int attributes = 0; // From SOVERSION 98, start to support custom wrapper domains, enabling the attribute bit if ( _domainVersionMap.size()>0 ) attributes |= 0x1; if ( _useSchemaData ) { attributes |= 0x2; // Record if we use inbuilt schema data or not useCompressSource = true; } // From SOVERSION 98, start to support binary begin/end brackets so we can easily ignore // errors and unsupport classes, enabling the attribute bit if ( _useRobustBinaryFormat ) { outIterator->setSupportBinaryBrackets( true ); attributes |= 0x4; } *this << attributes; // Record all custom versions if ( _domainVersionMap.size()>0 ) { unsigned int numDomains = _domainVersionMap.size(); *this << numDomains; for ( VersionMap::iterator itr=_domainVersionMap.begin(); itr!=_domainVersionMap.end(); ++itr ) { *this << itr->first << itr->second; } } if ( !_compressorName.empty() ) { BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName); if ( !compressor ) { OSG_WARN << "OutputStream::start(): No such compressor " << _compressorName << std::endl; _compressorName.clear(); } else { useCompressSource = true; } } if ( !_compressorName.empty() ) *this << _compressorName; else *this << std::string("0"); // No compressor // Compressors and inbuilt schema use a new stream, which will be merged with the original one at the end. if ( useCompressSource ) { _out->flush(); _out->setStream( &_compressSource ); } } else { std::string typeString("Unknown"); switch ( type ) { case WRITE_SCENE: typeString = "Scene"; break; case WRITE_IMAGE: typeString = "Image"; break; case WRITE_OBJECT: typeString = "Object"; break; default: break; } *this << typeString << std::endl; *this << PROPERTY("#Version") << (unsigned int)OPENSCENEGRAPH_SOVERSION << std::endl; *this << PROPERTY("#Generator") << std::string("OpenSceneGraph") << std::string(osgGetVersion()) << std::endl; if ( _domainVersionMap.size()>0 ) { for ( VersionMap::iterator itr=_domainVersionMap.begin(); itr!=_domainVersionMap.end(); ++itr ) { *this << PROPERTY("#CustomDomain") << itr->first << itr->second << std::endl; } } *this << std::endl; } _fields.pop_back(); } void OutputStream::compress( std::ostream* ostream ) { _fields.clear(); if ( !isBinary() ) return; std::stringstream schemaSource; if ( _useSchemaData ) { _fields.push_back( "SchemaData" ); std::string schemaData; for ( SchemaMap::iterator itr=_inbuiltSchemaMap.begin(); itr!=_inbuiltSchemaMap.end(); ++itr ) { schemaData += itr->first + '='; schemaData += itr->second; schemaData += '\n'; } int size = schemaData.size(); schemaSource.write( (char*)&size, INT_SIZE ); schemaSource.write( schemaData.c_str(), size ); _inbuiltSchemaMap.clear(); _fields.pop_back(); } if ( !_compressorName.empty() ) { _fields.push_back( "Compression" ); BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName); if ( !compressor || !ostream ) { _fields.pop_back(); return; } if ( !compressor->compress(*ostream, schemaSource.str() + _compressSource.str()) ) throwException( "OutputStream: Failed to compress stream." ); if ( getException() ) return; _fields.pop_back(); } else if ( _useSchemaData ) { std::string str = schemaSource.str() + _compressSource.str(); ostream->write( str.c_str(), str.size() ); } } void OutputStream::writeSchema( std::ostream& fout ) { // Write to external ascii stream const ObjectWrapperManager::WrapperMap& wrappers = Registry::instance()->getObjectWrapperManager()->getWrapperMap(); for ( ObjectWrapperManager::WrapperMap::const_iterator itr=wrappers.begin(); itr!=wrappers.end(); ++itr ) { ObjectWrapper* wrapper = itr->second.get(); fout << itr->first << " ="; StringList properties; ObjectWrapper::TypeList types; wrapper->writeSchema( properties, types ); std::string propertiesString; unsigned int size = osg::minimum( properties.size(), types.size() ); for ( unsigned int i=0; i void OutputStream::writeArrayImplementation( const T* a, int write_size, unsigned int numInRow ) { *this << write_size << BEGIN_BRACKET; if ( numInRow>1 ) { for ( int i=0; isecond; } unsigned int OutputStream::findOrCreateObjectID( const osg::Object* obj, bool& newID ) { ObjectMap::iterator itr = _objectMap.find( obj ); if ( itr==_objectMap.end() ) { unsigned int id = _objectMap.size()+1; _objectMap[obj] = id; newID = true; return id; } newID = false; return itr->second; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/FieldReaderIterator.cpp0000644000175000017500000003447013151044751025243 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include using namespace osgDB; FieldReaderIterator::FieldReaderIterator() { _init(); } FieldReaderIterator::FieldReaderIterator(const FieldReaderIterator& ic) { _copy(ic); } FieldReaderIterator::~FieldReaderIterator() { _free(); } FieldReaderIterator& FieldReaderIterator::operator = (const FieldReaderIterator& ic) { if (this==&ic) return *this; _free(); _copy(ic); return *this; } void FieldReaderIterator::_free() { // free all data if (_previousField) { delete _previousField; } if (_fieldQueue) { for(int i=0;i<_fieldQueueCapacity;++i) { if (_fieldQueue[i]) delete _fieldQueue[i]; _fieldQueue[i] = NULL; } delete [] _fieldQueue; } _init(); } void FieldReaderIterator::_init() { _previousField = NULL; _fieldQueue = NULL; _fieldQueueSize = 0; _fieldQueueCapacity = 0; } void FieldReaderIterator::_copy(const FieldReaderIterator& ic) { _reader = ic._reader; if (ic._previousField) { _previousField = new Field(*ic._previousField); } if (ic._fieldQueue && ic._fieldQueueCapacity>0) { _fieldQueue = new Field* [ic._fieldQueueCapacity]; for(int i=0;i_fieldQueueSize) pos=_fieldQueueSize; int i; // need to reallocate the stack if (_fieldQueueSize>=_fieldQueueCapacity) { int newCapacity = _fieldQueueCapacity*2; if (newCapacity=newCapacity) newCapacity*=2; Field** newFieldStack = new Field* [newCapacity]; for(i=0;i<_fieldQueueCapacity;++i) { newFieldStack[i] = _fieldQueue[i]; } for(;i=pos;++i) { _fieldQueue[i+1]=_fieldQueue[i]; } _fieldQueue[pos] = field; ++_fieldQueueSize; } void FieldReaderIterator::insert(int pos,const char* str) { if (str) { Field* field = new Field; while(*str!=0) { field->addChar(*str); ++str; } insert(pos,field); } } Field& FieldReaderIterator::operator [] (int pos) { return field(pos); } Field& FieldReaderIterator::field (int pos) { if (pos<0) { _blank.setNoNestedBrackets(_reader.getNoNestedBrackets()); return _blank; } // can directly access field else if (pos<_fieldQueueSize) { return *_fieldQueue[pos]; } // need to read the new fields. else { // need to reallocate the stack if (pos>=_fieldQueueCapacity) { int newCapacity = _fieldQueueCapacity*2; if (newCapacity=newCapacity) newCapacity*=2; Field** newFieldStack = new Field* [newCapacity]; int i; for(i=0;i<_fieldQueueCapacity;++i) { newFieldStack[i] = _fieldQueue[i]; } for(;i=_fieldQueueSize) { if (_fieldQueue[_fieldQueueSize]==NULL) _fieldQueue[_fieldQueueSize] = new Field; if (_reader.readField(*_fieldQueue[_fieldQueueSize])) { ++_fieldQueueSize; } } if (pos<_fieldQueueSize) { return *_fieldQueue[pos]; } else { _blank.setNoNestedBrackets(_reader.getNoNestedBrackets()); return _blank; } } } FieldReaderIterator& FieldReaderIterator::operator ++ () { return (*this)+=1; } FieldReaderIterator& FieldReaderIterator::operator += (int no) { if (no>_fieldQueueSize) { while (!_reader.eof() && no>_fieldQueueSize) { _reader.ignoreField(); --no; } _fieldQueueSize=0; } else if (no>0) { Field** tmpFields = new Field* [no]; int i; for(i=0;i=entry) { ++(*this); } } void FieldReaderIterator::advanceToEndOfBlock(int noNestedBrackets) { while(!eof() && field(0).getNoNestedBrackets()>=noNestedBrackets) { ++(*this); } } bool FieldReaderIterator::matchSequence(const char* str) { if (str==NULL) return false; if (*str==0) return false; int fieldCount = 0; const char* end = str; while((*end)!=0 && (*end)==' ') ++end; const char* start = end; while((*start)!=0) { if (*end!=' ' && *end!=0) { ++end; } else { if (start!=end) { if (end-start>1 && *start=='%') { const char type = *(start+1); switch(type) { // expecting an integer case('i') : { if (!field(fieldCount).isInt()) return false; break; } // expecting an floating point number case('f') : { if (!field(fieldCount).isFloat()) return false; break; } // expecting an quoted string case('s') : { if (!field(fieldCount).isQuotedString()) return false; break; } case('w') : default :// expecting an word { if (!field(fieldCount).isWord()) return false; break; } } } else { if (*start=='{') { if (!field(fieldCount).isOpenBracket()) return false; } else if (*start=='}') { if (!field(fieldCount).isCloseBracket()) return false; } else { if (!field(fieldCount).matchWord(start,end-start)) return false; } } fieldCount++; } while((*end)==' ') ++end; start = end; } } return true; } bool FieldReaderIterator::readSequence(const char* keyword,std::string& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].isString()) { value = (*this)[1].getStr(); (*this)+=2; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,unsigned int& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getUInt(value)) { (*this)+=2; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,int& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getInt(value)) { (*this)+=2; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,float& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value)) { (*this)+=2; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,osg::Vec2f& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value[0]) && (*this)[2].getFloat(value[1])) { (*this)+=3; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,osg::Vec3f& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value[0]) && (*this)[2].getFloat(value[1]) && (*this)[3].getFloat(value[2])) { (*this)+=4; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,osg::Vec4f& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value[0]) && (*this)[2].getFloat(value[1]) && (*this)[3].getFloat(value[2]) && (*this)[4].getFloat(value[3])) { (*this)+=5; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,osg::Vec2d& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value[0]) && (*this)[2].getFloat(value[1])) { (*this)+=3; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,osg::Vec3d& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value[0]) && (*this)[2].getFloat(value[1]) && (*this)[3].getFloat(value[2])) { (*this)+=4; return true; } return false; } bool FieldReaderIterator::readSequence(const char* keyword,osg::Vec4d& value) { if ((*this)[0].matchWord(keyword) && (*this)[1].getFloat(value[0]) && (*this)[2].getFloat(value[1]) && (*this)[3].getFloat(value[2]) && (*this)[4].getFloat(value[3])) { (*this)+=5; return true; } return false; } bool FieldReaderIterator::readSequence(std::string& value) { if ((*this)[0].isString()) { value = (*this)[0].getStr(); (*this)+=1; return true; } return false; } bool FieldReaderIterator::readSequence(unsigned int& value) { if ((*this)[0].getUInt(value)) { (*this)+=1; return true; } return false; } bool FieldReaderIterator::readSequence(int& value) { if ((*this)[0].getInt(value)) { (*this)+=1; return true; } return false; } bool FieldReaderIterator::readSequence(float& value) { if ((*this)[0].getFloat(value)) { (*this)+=1; return true; } return false; } bool FieldReaderIterator::readSequence(osg::Vec2f& value) { if ((*this)[0].getFloat(value[0]) && (*this)[1].getFloat(value[1])) { (*this)+=2; return true; } return false; } bool FieldReaderIterator::readSequence(osg::Vec3f& value) { if ((*this)[0].getFloat(value[0]) && (*this)[1].getFloat(value[1]) && (*this)[2].getFloat(value[2])) { (*this)+=3; return true; } return false; } bool FieldReaderIterator::readSequence(osg::Vec4f& value) { if ((*this)[0].getFloat(value[0]) && (*this)[1].getFloat(value[1]) && (*this)[2].getFloat(value[2]) && (*this)[3].getFloat(value[3])) { (*this)+=4; return true; } return false; } bool FieldReaderIterator::readSequence(osg::Vec2d& value) { if ((*this)[0].getFloat(value[0]) && (*this)[1].getFloat(value[1])) { (*this)+=2; return true; } return false; } bool FieldReaderIterator::readSequence(osg::Vec3d& value) { if ((*this)[0].getFloat(value[0]) && (*this)[1].getFloat(value[1]) && (*this)[2].getFloat(value[2])) { (*this)+=3; return true; } return false; } bool FieldReaderIterator::readSequence(osg::Vec4d& value) { if ((*this)[0].getFloat(value[0]) && (*this)[1].getFloat(value[1]) && (*this)[2].getFloat(value[2]) && (*this)[3].getFloat(value[3])) { (*this)+=4; return true; } return false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Field.cpp0000644000175000017500000002152513151044751022403 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include using namespace osgDB; using namespace std; Field::Field() { _init(); } Field::Field(const Field& ic) { _copy(ic); } Field::~Field() { _free(); } Field& Field::operator = (const Field& ic) { if (this==&ic) return *this; _free(); _copy(ic); return *this; } void Field::_free() { // free all data if (_fieldCache) delete [] _fieldCache; _init(); } void Field::_init() { _fieldCacheCapacity = 256; _fieldCacheSize = 0; _fieldCache = NULL; _fieldType = UNINITIALISED; _withinQuotes = false; _noNestedBrackets = 0; } void Field::_copy(const Field& ic) { // copy string cache. if (ic._fieldCache) { _fieldCacheCapacity = ic._fieldCacheCapacity; _fieldCacheSize = ic._fieldCacheSize; _fieldCache = new char [_fieldCacheCapacity]; strncpy(_fieldCache,ic._fieldCache,_fieldCacheCapacity); } else { _fieldCacheCapacity = 0; _fieldCacheSize = 0; _fieldCache = NULL; } _fieldType = ic._fieldType; _withinQuotes = ic._withinQuotes; _noNestedBrackets = ic._noNestedBrackets; } void Field::setWithinQuotes(bool withinQuotes) { _withinQuotes=withinQuotes; _fieldType = UNINITIALISED; } bool Field::getWithinQuotes() { return _withinQuotes; } void Field::setNoNestedBrackets(int no) { _noNestedBrackets=no; } int Field::getNoNestedBrackets() { return _noNestedBrackets; } const char* Field::getStr() const { if (_fieldCacheSize!=0) return _fieldCache; else return NULL; } char* Field::takeStr() { char* field = _fieldCache; _fieldCache = NULL; _fieldCacheSize = 0; _fieldType = UNINITIALISED; _withinQuotes = false; return field; } void Field::reset() { _fieldCacheSize = 0; if (_fieldCache) { _fieldCache[_fieldCacheSize] = 0; } _withinQuotes = false; _noNestedBrackets = 0; } void Field::addChar(char c) { if (_fieldCache==NULL) { if (_fieldCacheCapacity=_fieldCacheCapacity-1) { if (_fieldCacheCapacity=_fieldCacheCapacity-1) _fieldCacheCapacity *= 2; char* tmp_str = _fieldCache; _fieldCache = new char[_fieldCacheCapacity]; memset(_fieldCache,0,_fieldCacheCapacity); strncpy(_fieldCache,tmp_str,_fieldCacheSize); delete [] tmp_str; } _fieldCache[_fieldCacheSize++] = c; _fieldCache[_fieldCacheSize] = 0; _fieldType = UNINITIALISED; } Field::FieldType Field::getFieldType() const { if (_fieldType==UNINITIALISED && _fieldCache) { _fieldType = calculateFieldType(_fieldCache,_withinQuotes); } return _fieldType; } bool Field::isValid() const { if (_fieldCacheSize>0 && !_withinQuotes) return true; else return false; } bool Field::isOpenBracket() const { if (_fieldCacheSize==1) return _fieldCache[0]=='{'; else return false; } bool Field::isCloseBracket() const { if (_fieldCacheSize==1) return _fieldCache[0]=='}'; else return false; } bool Field::isWord() const { getFieldType(); return (_fieldType==WORD); } bool Field::matchWord(const char* str) const { getFieldType(); return _fieldType==WORD && strcmp(_fieldCache,str)==0; } bool Field::matchWord(const char* str,int noCharacters) const { getFieldType(); return _fieldType==WORD && strncmp(_fieldCache,str,noCharacters)==0; } bool Field::isString() const { return getNoCharacters()!=0; } bool Field::matchString(const char* str) const { return strcmp(_fieldCache,str)==0; } bool Field::matchString(const char* str,int noCharacters) const { return strncmp(_fieldCache,str,noCharacters)==0; } bool Field::isQuotedString() const { return _withinQuotes; } bool Field::isInt() const { getFieldType(); return _fieldType==INTEGER; } bool Field::matchInt(int i) const { getFieldType(); if (_fieldType==INTEGER) { return strtol(_fieldCache,NULL,0)==i; } else { return false; } } bool Field::getInt(int& i) const { getFieldType(); if (_fieldType==INTEGER) { i = strtol(_fieldCache,NULL,0); return true; } else { return false; } } bool Field::isUInt() const { getFieldType(); return _fieldType==INTEGER; } bool Field::matchUInt(unsigned int i) const { getFieldType(); if (_fieldType==INTEGER) { return (unsigned int) strtoul(_fieldCache,NULL,0)==i; } else { return false; } } bool Field::getUInt(unsigned int& i) const { getFieldType(); if (_fieldType==INTEGER) { i = strtoul(_fieldCache,NULL,0); return true; } else { return false; } } bool Field::isFloat() const { getFieldType(); return _fieldType==REAL || _fieldType==INTEGER; } bool Field::matchFloat(float f) const { getFieldType(); if (_fieldType==REAL || _fieldType==INTEGER) { return osg::asciiToFloat(_fieldCache)==f; } else { return false; } } bool Field::getFloat(float& f) const { getFieldType(); if (_fieldType==REAL || _fieldType==INTEGER) { f = osg::asciiToFloat(_fieldCache); return true; } else { return false; } } bool Field::getFloat(double& f) const { getFieldType(); if (_fieldType==REAL || _fieldType==INTEGER) { f = osg::asciiToDouble(_fieldCache); return true; } else { return false; } } Field::FieldType Field::calculateFieldType(const char* str,bool withinQuotes) { if (str==NULL) return BLANK; if (*str==0) return BLANK; if (withinQuotes) return STRING; bool hadPlusMinus = false; bool hadDecimalPlace = false; bool hadExponent = false; bool couldBeInt = true; bool couldBeFloat = true; int noZeroToNine = 0; const char* ptr = str; // check if could be a hex number. if (strncmp(ptr,"0x",2)==0) { // skip over leading 0x, and then go through rest of string // checking to make sure all values are 0...9 or a..f. ptr+=2; while ( *ptr!=0 && ((*ptr>='0' && *ptr<='9') || (*ptr>='a' && *ptr<='f') || (*ptr>='A' && *ptr<='F')) ) { ++ptr; } // got to end of string without failure, therefore must be a hex integer. if (*ptr==0) return INTEGER; } ptr = str; // check if a float or an int. while (*ptr!=0 && couldBeFloat) { if (*ptr=='+' || *ptr=='-') { if (hadPlusMinus) { couldBeInt = false; couldBeFloat = false; } else hadPlusMinus = true; } else if (*ptr>='0' && *ptr<='9') { noZeroToNine++; } else if (*ptr=='.') { if (hadDecimalPlace) { couldBeInt = false; couldBeFloat = false; } else { hadDecimalPlace = true; couldBeInt = false; } } else if (*ptr=='e' || *ptr=='E') { if (hadExponent || noZeroToNine==0) { couldBeInt = false; couldBeFloat = false; } else { hadExponent = true; couldBeInt = false; hadDecimalPlace = false; hadPlusMinus = false; noZeroToNine=0; } } else { couldBeInt = false; couldBeFloat = false; } ++ptr; } if (couldBeInt && noZeroToNine>0) return INTEGER; if (couldBeFloat && noZeroToNine>0) return REAL; if (str[0]=='{') return OPEN_BRACKET; if (str[0]=='}') return CLOSE_BRACKET; return WORD; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/CMakeLists.txt0000644000175000017500000001142513151044751023412 0ustar albertoalberto IF (DYNAMIC_OPENSCENEGRAPH) OPTION(OSG_PLUGIN_SEARCH_INSTALL_DIR_FOR_PLUGINS "Set to ON to have OpenSceneGraph search the configured install directory for plugins." ON) ADD_DEFINITIONS(-DOSGDB_LIBRARY) IF(OSG_PLUGIN_SEARCH_INSTALL_DIR_FOR_PLUGINS) # Add a default plugin search path component ADD_DEFINITIONS(-DOSG_DEFAULT_LIBRARY_PATH=\"${CMAKE_INSTALL_PREFIX}/lib${LIB_POSTFIX}/${OSG_PLUGINS}\") ENDIF() # Set the library extension according to what configuration is being built. # If the string is empty, don't set the define. IF(CMAKE_DEBUG_POSTFIX) SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOSG_LIBRARY_POSTFIX=${CMAKE_DEBUG_POSTFIX}") ENDIF() IF(CMAKE_RELEASE_POSTFIX) SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DOSG_LIBRARY_POSTFIX=${CMAKE_RELEASE_POSTFIX}") ENDIF() IF(CMAKE_RELWITHDEBINFO_POSTFIX) SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DOSG_LIBRARY_POSTFIX=${CMAKE_RELWITHDEBINFO_POSTFIX}") ENDIF() IF(CMAKE_MINSIZEREL_POSTFIX) SET(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -DOSG_LIBRARY_POSTFIX=${CMAKE_MINSIZEREL_POSTFIX}") ENDIF() ELSE () ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) ENDIF() IF(APPLE AND NOT ANDROID) # compile FileUtils.cpp as objective-c++ SET_SOURCE_FILES_PROPERTIES(FileUtils.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++" ) ENDIF() SET(LIB_NAME osgDB) SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) SET(TARGET_H ${HEADER_PATH}/DataTypes ${HEADER_PATH}/StreamOperator ${HEADER_PATH}/Serializer ${HEADER_PATH}/ObjectWrapper ${HEADER_PATH}/InputStream ${HEADER_PATH}/OutputStream ${HEADER_PATH}/Archive ${HEADER_PATH}/AuthenticationMap ${HEADER_PATH}/Callbacks ${HEADER_PATH}/ClassInterface ${HEADER_PATH}/ConvertBase64 ${HEADER_PATH}/ConvertUTF ${HEADER_PATH}/DatabasePager ${HEADER_PATH}/DatabaseRevisions ${HEADER_PATH}/DotOsgWrapper ${HEADER_PATH}/DynamicLibrary ${HEADER_PATH}/Export ${HEADER_PATH}/ExternalFileWriter ${HEADER_PATH}/FileCache ${HEADER_PATH}/FileNameUtils ${HEADER_PATH}/FileUtils ${HEADER_PATH}/fstream ${HEADER_PATH}/ImageOptions ${HEADER_PATH}/ImagePager ${HEADER_PATH}/ImageProcessor ${HEADER_PATH}/Input ${HEADER_PATH}/ObjectCache ${HEADER_PATH}/Output ${HEADER_PATH}/Options ${HEADER_PATH}/ParameterOutput ${HEADER_PATH}/PluginQuery ${HEADER_PATH}/ReaderWriter ${HEADER_PATH}/ReadFile ${HEADER_PATH}/Registry ${HEADER_PATH}/SharedStateManager ${HEADER_PATH}/Version ${HEADER_PATH}/WriteFile ${HEADER_PATH}/XmlParser ) SET(TARGET_SRC ObjectWrapper.cpp InputStream.cpp OutputStream.cpp Compressors.cpp Archive.cpp AuthenticationMap.cpp Callbacks.cpp ClassInterface.cpp ConvertBase64.cpp ConvertUTF.cpp DatabasePager.cpp DatabaseRevisions.cpp DotOsgWrapper.cpp DynamicLibrary.cpp ExternalFileWriter.cpp Field.cpp FieldReader.cpp FieldReaderIterator.cpp FileCache.cpp FileNameUtils.cpp FileUtils.cpp fstream.cpp ImageOptions.cpp ImagePager.cpp Input.cpp MimeTypes.cpp ObjectCache.cpp Output.cpp Options.cpp PluginQuery.cpp ReaderWriter.cpp ReadFile.cpp Registry.cpp SharedStateManager.cpp StreamOperator.cpp Version.cpp WriteFile.cpp XmlParser.cpp ${OPENSCENEGRAPH_VERSIONINFO_RC} ) IF(APPLE AND NOT ANDROID) IF(NOT OSG_BUILD_PLATFORM_IPHONE AND NOT OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) # Needs CoreFoundation calls and a Carbon function SET(OSGDB_PLATFORM_SPECIFIC_LIBRARIES ${CARBON_LIBRARY} ${COCOA_LIBRARY}) ENDIF() IF(OSG_DEFAULT_IMAGE_PLUGIN_FOR_OSX STREQUAL "quicktime") ADD_DEFINITIONS(-DDARWIN_QUICKTIME) ELSE() ADD_DEFINITIONS(-DDARWIN_IMAGEIO) ENDIF() ENDIF() IF(QTKIT_FOUND) ADD_DEFINITIONS(-DUSE_QTKIT) ENDIF() IF(QUICKTIME_FOUND) ADD_DEFINITIONS(-DUSE_QUICKTIME) ENDIF() IF(AV_FOUNDATION_FOUND) ADD_DEFINITIONS(-DUSE_AV_FOUNDATION) ENDIF() IF(XINE_FOUND) ADD_DEFINITIONS(-DUSE_XINE) ENDIF() IF(INVENTOR_FOUND) ADD_DEFINITIONS(-DUSE_INVENTOR) ENDIF() IF(OPENVRML_FOUND) ADD_DEFINITIONS(-DUSE_VRML) ENDIF() IF( ZLIB_FOUND ) ADD_DEFINITIONS( -DUSE_ZLIB ) INCLUDE_DIRECTORIES( ${ZLIB_INCLUDE_DIR} ) SET(COMPRESSION_LIBRARIES ZLIB_LIBRARY) ENDIF() ADD_DEFINITIONS(-DOSG_PLUGIN_EXTENSION=${CMAKE_SHARED_MODULE_SUFFIX}) SET(TARGET_LIBRARIES osg osgUtil OpenThreads ) SET(TARGET_EXTERNAL_LIBRARIES ${OSGDB_PLATFORM_SPECIFIC_LIBRARIES} ${DL_LIBRARY}) SET(TARGET_LIBRARIES_VARS ${COMPRESSION_LIBRARIES}) SETUP_LIBRARY(${LIB_NAME}) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/AuthenticationMap.cpp0000644000175000017500000000303113151044751024765 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgDB; void AuthenticationMap::addAuthenticationDetails(const std::string& path, AuthenticationDetails* details) { _authenticationMap[path] = details; } const AuthenticationDetails* AuthenticationMap::getAuthenticationDetails(const std::string& path) const { // see if the full filename has its own authentication details AuthenticationDetailsMap::const_iterator itr = _authenticationMap.find(path); if (itr != _authenticationMap.end()) return itr->second.get(); // now look to see if the paths to the file have their own authentication details std::string basePath = osgDB::getFilePath(path); while(!basePath.empty()) { itr = _authenticationMap.find(basePath); if (itr != _authenticationMap.end()) return itr->second.get(); basePath = osgDB::getFilePath(basePath); } return 0; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/MimeTypes.cpp0000644000175000017500000000742613151044751023300 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ const char* builtinMimeTypeExtMappings[] = { "application/dxf","dxf", "application/gnutar","tgz", "application/pdf","pdf", "application/plain","text", "application/postscript","ps", "application/x-bzip","bz", "application/x-bzip2","bz2", "application/x-compressed","zip", "application/x-gzip","gz", "application/x-inventor","iv", "application/x-javascript","js", "application/xml","xml", "application/x-tar","tar", "application/x-vrml","wrl", "application/x-world","wrl", "application/x-zip-compressed","zip", "application/zip","zip", "drawing/x-dwf(old)","dwf", "image/bmp","bmp", "image/cmu-raster","ras", "image/fif","fif", "image/florian","flo", "image/g3fax","g3", "image/gif","gif", "image/ief","ief", "image/jpeg","jpg", "image/jutvision","jut", "image/naplps","nap", "image/naplps","naplps", "image/pict","pic", "image/pjpeg","jpg", "image/png","png", "image/tiff","tif", "image/vasa","mcf", "image/vnd.dwg","dxf", "image/vnd.fpx","fpx", "image/vnd.net-fpx","fpx", "image/vnd.rn-realflash","rf", "image/vnd.rn-realpix","rp", "image/vnd.wap.wbmp","wbmp", "image/vnd.xiff","xif", "image/xbm","xbm", "image/x-cmu-raster","ras", "image/x-dwg","dxf", "image/x-icon","ico", "image/x-jg","art", "image/x-jps","jps", "image/x-niff","nif", "image/x-pcx","pcx", "image/x-pict","pct", "image/xpm","xpm", "image/x-portable-anymap","pnm", "image/x-portable-bitmap","pbm", "image/x-portable-graymap","pgm", "image/x-portable-greymap","pgm", "image/x-portable-pixmap","ppm", "image/x-quicktime","qif", "image/x-rgb","rgb", "image/x-tiff","tif", "image/x-windows-bmp","bmp", "image/x-xbitmap","xbm", "image/x-xbm","xbm", "image/x-xpixmap","xpm", "image/x-xwd","xwd", "image/x-xwindowdump","xwd", "i-world/i-vrml","ivr", "model/iges","igs", "model/vnd.dwf","dwf", "model/vrml","wrl", "model/x-pov","pov", "multipart/x-gzip","gzip", "multipart/x-ustar","ustar", "multipart/x-zip","zip", "video/animaflex","afl", "video/avi","avi", "video/avs-video","avs", "video/dl","dl", "video/fli","fli", "video/gl","gl", "video/mpeg","mpg", "video/msvideo","avi", "video/quicktime","qt", "video/vdo","vdo", "video/vivo","viv", "video/vnd.rn-realvideo","rv", "video/vnd.vivo","viv", "video/vosaic","vos", "video/x-amt-demorun","xdr", "video/x-amt-showrun","xsr", "video/x-atomic3d-feature","fmf", "video/x-dl","dl", "video/x-dv","dv", "video/x-fli","fli", "video/x-gl","gl", "video/x-isvideo","isu", "video/x-motion-jpeg","mjpg", "video/x-mpeg","mp3", "video/x-mpeq2a","mp2", "video/x-ms-asf","asf", "video/x-ms-asf-plugin","asx", "video/x-msvideo","avi", "video/x-qtc","qtc", "video/x-scm","scm", "video/x-sgi-movie","movie", "windows/metafile","wmf", "xgl/drawing","xgz", "xgl/movie","xmz", "x-world/x-3dmf","3dm", "x-world/x-svr","svr", "x-world/x-vrml","wrl", "x-world/x-vrt","vrt", "" // end of list }; OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Input.cpp0000644000175000017500000003137213151044751022460 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include using namespace osgDB; Input::Input() { } Input::~Input() { } osg::Object* Input::getObjectForUniqueID(const std::string& uniqueID) { UniqueIDToObjectMapping::iterator fitr = _uniqueIDToObjectMap.find(uniqueID); if (fitr != _uniqueIDToObjectMap.end()) return (*fitr).second.get(); else return NULL; } void Input::registerUniqueIDForObject(const std::string& uniqueID,osg::Object* obj) { _uniqueIDToObjectMap[uniqueID] = obj; } osg::Object* Input::readObjectOfType(const osg::Object& compObj) { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readObjectOfType(compObj,*this); } osg::Object* Input::readObjectOfType(const basic_type_wrapper &btw) { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readObjectOfType(btw,*this); } osg::Object* Input::readObject() { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readObject(*this); } osg::Image* Input::readImage() { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readImage(*this); } osg::Drawable* Input::readDrawable() { osg::Drawable* drawable = Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readDrawable(*this); osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0; if (geometry && geometry->containsDeprecatedData()) geometry->fixDeprecatedData(); return drawable; } osg::StateAttribute* Input::readStateAttribute() { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readStateAttribute(*this); } osg::Uniform* Input::readUniform() { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readUniform(*this); } osg::Node* Input::readNode() { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readNode(*this); } osg::Object* Input::readObject(const std::string& fileName) { return readRefObjectFile(fileName,_options.get()).release(); } osg::Shader* Input::readShader() { return Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->readShader(*this); } osg::Image* Input::readImage(const std::string& fileName) { return readRefImageFile(fileName,_options.get()).release(); } osg::Node* Input::readNode(const std::string& fileName) { return readRefNodeFile(fileName,_options.get()).release(); } osg::Shader* Input::readShader(const std::string& fileName) { return readRefShaderFile(fileName,_options.get()).release(); } bool Input::read(Parameter value1) { if (value1.valid((*this)[0].getStr())) { value1.assign((*this)[0].getStr()); (*this) += 1; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); (*this) += 2; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2, Parameter value3) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr()) && value3.valid((*this)[2].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); value3.assign((*this)[2].getStr()); (*this) += 3; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2, Parameter value3, Parameter value4) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr()) && value3.valid((*this)[2].getStr()) && value4.valid((*this)[3].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); value3.assign((*this)[2].getStr()); value4.assign((*this)[3].getStr()); (*this) += 4; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr()) && value3.valid((*this)[2].getStr()) && value4.valid((*this)[3].getStr()) && value5.valid((*this)[4].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); value3.assign((*this)[2].getStr()); value4.assign((*this)[3].getStr()); value5.assign((*this)[4].getStr()); (*this) += 5; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr()) && value3.valid((*this)[2].getStr()) && value4.valid((*this)[3].getStr()) && value5.valid((*this)[4].getStr()) && value6.valid((*this)[5].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); value3.assign((*this)[2].getStr()); value4.assign((*this)[3].getStr()); value5.assign((*this)[4].getStr()); value6.assign((*this)[5].getStr()); (*this) += 6; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr()) && value3.valid((*this)[2].getStr()) && value4.valid((*this)[3].getStr()) && value5.valid((*this)[4].getStr()) && value6.valid((*this)[5].getStr()) && value7.valid((*this)[6].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); value3.assign((*this)[2].getStr()); value4.assign((*this)[3].getStr()); value5.assign((*this)[4].getStr()); value6.assign((*this)[5].getStr()); value7.assign((*this)[6].getStr()); (*this) += 7; return true; } else return false; } bool Input::read(Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7, Parameter value8) { if (value1.valid((*this)[0].getStr()) && value2.valid((*this)[1].getStr()) && value3.valid((*this)[2].getStr()) && value4.valid((*this)[3].getStr()) && value5.valid((*this)[4].getStr()) && value6.valid((*this)[5].getStr()) && value7.valid((*this)[6].getStr()) && value8.valid((*this)[7].getStr())) { value1.assign((*this)[0].getStr()); value2.assign((*this)[1].getStr()); value3.assign((*this)[2].getStr()); value4.assign((*this)[3].getStr()); value5.assign((*this)[4].getStr()); value6.assign((*this)[5].getStr()); value7.assign((*this)[6].getStr()); value8.assign((*this)[7].getStr()); (*this) += 8; return true; } else return false; } bool Input::read(const char* str) { if ((*this)[0].matchWord(str)) { (*this) += 1; return true; } else return false; } bool Input::read(const char* str, Parameter value1) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr())) { value1.assign((*this)[1].getStr()); (*this) += 2; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); (*this) += 3; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2, Parameter value3) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr()) && value3.valid((*this)[3].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); value3.assign((*this)[3].getStr()); (*this) += 4; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2, Parameter value3, Parameter value4) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr()) && value3.valid((*this)[3].getStr()) && value4.valid((*this)[4].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); value3.assign((*this)[3].getStr()); value4.assign((*this)[4].getStr()); (*this) += 5; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr()) && value3.valid((*this)[3].getStr()) && value4.valid((*this)[4].getStr()) && value5.valid((*this)[5].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); value3.assign((*this)[3].getStr()); value4.assign((*this)[4].getStr()); value5.assign((*this)[5].getStr()); (*this) += 6; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr()) && value3.valid((*this)[3].getStr()) && value4.valid((*this)[4].getStr()) && value5.valid((*this)[5].getStr()) && value6.valid((*this)[6].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); value3.assign((*this)[3].getStr()); value4.assign((*this)[4].getStr()); value5.assign((*this)[5].getStr()); value6.assign((*this)[6].getStr()); (*this) += 7; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr()) && value3.valid((*this)[3].getStr()) && value4.valid((*this)[4].getStr()) && value5.valid((*this)[5].getStr()) && value6.valid((*this)[6].getStr()) && value7.valid((*this)[7].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); value3.assign((*this)[3].getStr()); value4.assign((*this)[4].getStr()); value5.assign((*this)[5].getStr()); value6.assign((*this)[6].getStr()); value7.assign((*this)[7].getStr()); (*this) += 8; return true; } else return false; } bool Input::read(const char* str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7, Parameter value8) { if ((*this)[0].matchWord(str) && value1.valid((*this)[1].getStr()) && value2.valid((*this)[2].getStr()) && value3.valid((*this)[3].getStr()) && value4.valid((*this)[4].getStr()) && value5.valid((*this)[5].getStr()) && value6.valid((*this)[6].getStr()) && value7.valid((*this)[7].getStr()) && value8.valid((*this)[8].getStr())) { value1.assign((*this)[1].getStr()); value2.assign((*this)[2].getStr()); value3.assign((*this)[3].getStr()); value4.assign((*this)[4].getStr()); value5.assign((*this)[5].getStr()); value6.assign((*this)[6].getStr()); value7.assign((*this)[7].getStr()); value8.assign((*this)[8].getStr()); (*this) += 9; return true; } else return false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/ObjectCache.cpp0000644000175000017500000001046013151044751023506 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include using namespace osgDB; //////////////////////////////////////////////////////////////////////////////////////////// // // ObjectCache // ObjectCache::ObjectCache(): osg::Referenced(true) { // OSG_NOTICE<<"Constructed ObjectCache"< lock1(_objectCacheMutex); OpenThreads::ScopedLock lock2(objectCache->_objectCacheMutex); // OSG_NOTICE<<"Inserting objects to main ObjectCache "<_objectCache.size()<_objectCache.begin(), objectCache->_objectCache.end()); } void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache[filename]=ObjectTimeStampPair(object,timestamp); } osg::Object* ObjectCache::getFromObjectCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_objectCacheMutex); ObjectCacheMap::iterator itr = _objectCache.find(fileName); if (itr!=_objectCache.end()) return itr->second.first.get(); else return 0; } osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_objectCacheMutex); ObjectCacheMap::iterator itr = _objectCache.find(fileName); if (itr!=_objectCache.end()) { // OSG_NOTICE<<"Found "<second.first; } else return 0; } void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) { OpenThreads::ScopedLock lock(_objectCacheMutex); // look for objects with external references and update their time stamp. for(ObjectCacheMap::iterator itr=_objectCache.begin(); itr!=_objectCache.end(); ++itr) { // if ref count is greater the 1 the object has an external reference. if (itr->second.first->referenceCount()>1) { // so update it time stamp. itr->second.second = referenceTime; } } } void ObjectCache::removeExpiredObjectsInCache(double expiryTime) { OpenThreads::ScopedLock lock(_objectCacheMutex); // Remove expired entries from object cache ObjectCacheMap::iterator oitr = _objectCache.begin(); while(oitr != _objectCache.end()) { if (oitr->second.second<=expiryTime) { _objectCache.erase(oitr++); } else { ++oitr; } } } void ObjectCache::removeFromObjectCache(const std::string& fileName) { OpenThreads::ScopedLock lock(_objectCacheMutex); ObjectCacheMap::iterator itr = _objectCache.find(fileName); if (itr!=_objectCache.end()) _objectCache.erase(itr); } void ObjectCache::clear() { OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache.clear(); } void ObjectCache::releaseGLObjects(osg::State* state) { OpenThreads::ScopedLock lock(_objectCacheMutex); for(ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr) { osg::Object* object = itr->second.first.get(); object->releaseGLObjects(state); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/ReadFile.cpp0000644000175000017500000002506213151044751023033 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osg; using namespace osgDB; #ifdef OSG_PROVIDE_READFILE Object* osgDB::readObjectFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readObject(filename,options); if (rr.validObject()) return rr.takeObject(); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } Image* osgDB::readImageFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readImage(filename,options); if (rr.validImage()) return rr.takeImage(); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } Shader* osgDB::readShaderFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readShader(filename,options); if (rr.validShader()) return rr.takeShader(); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } HeightField* osgDB::readHeightFieldFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readHeightField(filename,options); if (rr.validHeightField()) return rr.takeHeightField(); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } Node* osgDB::readNodeFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readNode(filename,options); if (rr.validNode()) return rr.takeNode(); if (rr.error()) OSG_WARN << rr.message() << std::endl; if (rr.notEnoughMemory()) OSG_INFO << "Not enought memory to load file "<& fileList,const Options* options) { return readRefNodeFiles(fileList, options).release(); } Node* osgDB::readNodeFiles(osg::ArgumentParser& arguments,const Options* options) { return readRefNodeFiles(arguments, options).release(); } Script* osgDB::readScriptFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readScript(filename,options); if (rr.validScript()) return rr.takeScript(); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } #endif osg::ref_ptr osgDB::readRefObjectFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readObject(filename,options); if (rr.validObject()) return osg::ref_ptr(rr.getObject()); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } osg::ref_ptr osgDB::readRefImageFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readImage(filename,options); if (rr.validImage()) return osg::ref_ptr(rr.getImage()); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } osg::ref_ptr osgDB::readRefShaderFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readShader(filename,options); if (rr.validShader()) return osg::ref_ptr(rr.getShader()); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } osg::ref_ptr osgDB::readRefHeightFieldFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readHeightField(filename,options); if (rr.validHeightField()) return osg::ref_ptr(rr.getHeightField()); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } osg::ref_ptr osgDB::readRefNodeFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readNode(filename,options); if (rr.validNode()) return osg::ref_ptr(rr.getNode()); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } osg::ref_ptr osgDB::readRefScriptFile(const std::string& filename,const Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readScript(filename,options); if (rr.validScript()) return osg::ref_ptr(rr.getScript()); if (rr.error()) OSG_WARN << rr.message() << std::endl; return NULL; } osg::ref_ptr osgDB::readRefNodeFiles(std::vector& fileList,const Options* options) { typedef std::vector< osg::ref_ptr > NodeList; NodeList nodeList; for(std::vector::iterator itr=fileList.begin(); itr!=fileList.end(); ++itr) { osg::ref_ptr node = osgDB::readRefNodeFile( *itr , options ); if( node != (osg::Node *)0L ) { if (node->getName().empty()) node->setName( *itr ); nodeList.push_back(node); } } if (nodeList.empty()) { return NULL; } if (nodeList.size()==1) { return nodeList.front(); } else // size >1 { osg::ref_ptr group = new osg::Group; for(NodeList::iterator itr=nodeList.begin(); itr!=nodeList.end(); ++itr) { group->addChild(*itr); } return group; } } osg::ref_ptr osgDB::readRefNodeFiles(osg::ArgumentParser& arguments,const Options* options) { typedef std::vector< osg::ref_ptr > NodeList; NodeList nodeList; std::string filename; while (arguments.read("--file-cache",filename)) { osgDB::Registry::instance()->setFileCache(new osgDB::FileCache(filename)); } while (arguments.read("--image",filename)) { osg::ref_ptr image = readRefImageFile(filename.c_str(), options); if (image.valid()) { osg::Geode* geode = osg::createGeodeForImage(image.get()); if (image->isImageTranslucent()) { OSG_INFO<<"Image "<getFileName()<<" is translucent; setting up blending."<getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); geode->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } nodeList.push_back(geode); } } while (arguments.read("--movie",filename)) { osg::ref_ptr image = readRefImageFile(filename.c_str(), options); osg::ref_ptr imageStream = dynamic_cast(image.get()); if (imageStream.valid()) { bool flip = image->getOrigin()==osg::Image::TOP_LEFT; // start the stream playing. imageStream->play(); osg::ref_ptr pictureQuad = 0; bool useTextureRectangle = true; if (useTextureRectangle) { pictureQuad = osg::createTexturedQuadGeometry(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(image->s(),0.0f,0.0f), osg::Vec3(0.0f,0.0f,image->t()), 0.0f, flip ? image->t() : 0.0, image->s(), flip ? 0.0 : image->t()); pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::TextureRectangle(image.get()), osg::StateAttribute::ON); } else { pictureQuad = osg::createTexturedQuadGeometry(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(image->s(),0.0f,0.0f), osg::Vec3(0.0f,0.0f,image->t()), 0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f); pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(image.get()), osg::StateAttribute::ON); } if (pictureQuad.valid()) { osg::ref_ptr geode = new osg::Geode; geode->addDrawable(pictureQuad.get()); nodeList.push_back(geode.get()); } } else if (image.valid()) { nodeList.push_back(osg::createGeodeForImage(image.get())); } } while (arguments.read("--dem",filename)) { osg::ref_ptr hf = readRefHeightFieldFile(filename.c_str(), options); if (hf) { osg::ref_ptr geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(hf.get())); nodeList.push_back(geode); } } // note currently doesn't delete the loaded file entries from the command line yet... for(int pos=1;pos node = osgDB::readRefNodeFile( arguments[pos], options); if(node) { if (node->getName().empty()) node->setName( arguments[pos] ); nodeList.push_back(node); } } } if (nodeList.empty()) { return NULL; } if (nodeList.size()==1) { return nodeList.front().release(); } else // size >1 { osg::ref_ptr group = new osg::Group; for(NodeList::iterator itr=nodeList.begin(); itr!=nodeList.end(); ++itr) { group->addChild(*itr); } return group; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/StreamOperator.cpp0000644000175000017500000000305613151044751024326 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgDB; void InputIterator::readComponentArray( char* s, unsigned int numElements, unsigned int numComponentsPerElements, unsigned int componentSizeInBytes) { unsigned int size = numElements * numComponentsPerElements * componentSizeInBytes; if ( size>0 ) { readCharArray( s, size); if (_byteSwap && componentSizeInBytes>1) { char* ptr = s; for(unsigned int i=0; ithrowException(msg); else OSG_WARN << msg << std::endl; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Options.cpp0000644000175000017500000000420113151044751023003 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgDB; Options::Options(const Options& options,const osg::CopyOp& copyop): osg::Object(options,copyop), _str(options._str), _databasePaths(options._databasePaths), _objectCacheHint(options._objectCacheHint), _objectCache(options._objectCache), _precisionHint(options._precisionHint), _buildKdTreesHint(options._buildKdTreesHint), _pluginData(options._pluginData), _pluginStringData(options._pluginStringData), _findFileCallback(options._findFileCallback), _readFileCallback(options._readFileCallback), _writeFileCallback(options._writeFileCallback), _fileLocationCallback(options._fileLocationCallback), _fileCache(options._fileCache), _terrain(options._terrain), _parentGroup(options._parentGroup) {} void Options::parsePluginStringData(const std::string& str, char separator1, char separator2) { StringList valueList; split(str, valueList, separator1); if (valueList.size() > 0) { StringList keyAndValue; for (StringList::iterator itr=valueList.begin(); itr!=valueList.end(); ++itr) { split(*itr, keyAndValue, separator2); if (keyAndValue.size() > 1) { setPluginStringData(keyAndValue.front(), keyAndValue.back()); } else if (keyAndValue.size() > 0) { setPluginStringData(keyAndValue.front(), "true"); } keyAndValue.clear(); } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/ObjectWrapper.cpp0000644000175000017500000007220413151044751024127 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // Written by Wang Rui, (C) 2010 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // pull in OSG headers to just introduce their GL defines for GL3/GLES compatibility #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef GL_PERSPECTIVE_CORRECTION_HINT #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 #endif #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) #define GL_POLYGON_SMOOTH_HINT 0x0C53 #define GL_LINE_SMOOTH_HINT 0x0C52 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #endif using namespace osgDB; void osgDB::split( const std::string& src, StringList& list, char separator ) { std::string::size_type start = src.find_first_not_of(separator); while ( start!=std::string::npos ) { std::string::size_type end = src.find_first_of(separator, start); if ( end!=std::string::npos ) { list.push_back( std::string(src, start, end-start) ); start = src.find_first_not_of(separator, end); } else { list.push_back( std::string(src, start, src.size()-start) ); start = end; } } } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // ObjectWrapper // ObjectWrapper::ObjectWrapper( CreateInstanceFunc* createInstanceFunc, const std::string& name, const std::string& associates ) : osg::Referenced(), _createInstanceFunc(createInstanceFunc), _name(name), _version(0) { split( associates, _associates ); } ObjectWrapper::ObjectWrapper( CreateInstanceFunc* createInstanceFunc, const std::string& domain, const std::string& name, const std::string& associates ) : osg::Referenced(), _createInstanceFunc(createInstanceFunc), _domain(domain), _name(name), _version(0) { split( associates, _associates ); } void ObjectWrapper::addSerializer( BaseSerializer* s, BaseSerializer::Type t ) { s->_firstVersion = _version; _serializers.push_back(s); _typeList.push_back(t); } void ObjectWrapper::markSerializerAsRemoved( const std::string& name ) { for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) { // When a serializer is marked as 'removed', it means that this serializer won't be used any more // from specified OSG version (by macro UPDATE_TO_VERSION). The read() functions of higher versions // will thus ignore it according to the sign and value of the _version variable. if ( (*itr)->getName()==name ) (*itr)->_lastVersion = _version-1; } } BaseSerializer* ObjectWrapper::getSerializer( const std::string& name ) { for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) { if ( (*itr)->getName()==name ) return itr->get(); } for ( StringList::const_iterator itr=_associates.begin(); itr!=_associates.end(); ++itr ) { const std::string& assocName = *itr; ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName); if ( !assocWrapper ) { osg::notify(osg::WARN) << "ObjectWrapper::getSerializer(): Unsupported associated class " << assocName << std::endl; continue; } for ( SerializerList::iterator aitr=assocWrapper->_serializers.begin(); aitr!=assocWrapper->_serializers.end(); ++aitr ) { if ( (*aitr)->getName()==name ) return aitr->get(); } } return NULL; } BaseSerializer* ObjectWrapper::getSerializer( const std::string& name, BaseSerializer::Type& type) { unsigned int i = 0; for (SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr, ++i ) { if ( (*itr)->getName()==name ) { type = _typeList[i]; return itr->get(); } } for ( StringList::const_iterator itr=_associates.begin(); itr!=_associates.end(); ++itr ) { const std::string& assocName = *itr; ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName); if ( !assocWrapper ) { osg::notify(osg::WARN) << "ObjectWrapper::getSerializer(): Unsupported associated class " << assocName << std::endl; continue; } i = 0; for ( SerializerList::iterator aitr=assocWrapper->_serializers.begin(); aitr!=assocWrapper->_serializers.end(); ++aitr, ++i ) { if ( (*aitr)->getName()==name ) { type = assocWrapper->_typeList[i]; return aitr->get(); } } } type = BaseSerializer::RW_UNDEFINED; return NULL; } bool ObjectWrapper::read( InputStream& is, osg::Object& obj ) { bool readOK = true; int inputVersion = is.getFileVersion(_domain); for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) { BaseSerializer* serializer = itr->get(); if ( serializer->_firstVersion <= inputVersion && inputVersion <= serializer->_lastVersion && serializer->supportsReadWrite()) { if ( !serializer->read(is, obj) ) { OSG_WARN << "ObjectWrapper::read(): Error reading property " << _name << "::" << (*itr)->getName() << std::endl; readOK = false; } } else { // OSG_NOTICE<<"Ignoring serializer due to version mismatch"<objectRead(is, obj); } return readOK; } bool ObjectWrapper::write( OutputStream& os, const osg::Object& obj ) { bool writeOK = true; int outputVersion = os.getFileVersion(_domain); for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) { BaseSerializer* serializer = itr->get(); if ( serializer->_firstVersion <= outputVersion && outputVersion <= serializer->_lastVersion && serializer->supportsReadWrite()) { if ( !serializer->write(os, obj) ) { OSG_WARN << "ObjectWrapper::write(): Error writing property " << _name << "::" << (*itr)->getName() << std::endl; writeOK = false; } } else { // OSG_NOTICE<<"Ignoring serializer due to version mismatch"<getName() ) { _serializers.push_back( _backupSerializers[i] ); } else { bool hasSerializer = false; for ( SerializerList::iterator itr=_backupSerializers.begin(); itr!=_backupSerializers.end(); ++itr ) { if ( prop!=(*itr)->getName() ) continue; _serializers.push_back( *itr ); hasSerializer = true; } if ( !hasSerializer ) { OSG_WARN << "ObjectWrapper::readSchema(): Wrapper " << _name << ": Unknown property " << prop << std::endl; } } } return size==_serializers.size(); } void ObjectWrapper::writeSchema( StringList& properties, TypeList& types ) { SerializerList::iterator sitr = _serializers.begin(); TypeList::iterator titr = _typeList.begin(); while(sitr!=_serializers.end() && titr!=_typeList.end()) { if ((*sitr)->supportsReadWrite()) { properties.push_back( (*sitr)->getName() ); types.push_back( (*titr) ); } ++sitr; ++titr; } } void ObjectWrapper::addMethodObject(const std::string& methodName, MethodObject* mo) { _methodObjectMap.insert(MethodObjectMap::value_type(methodName, mo)); } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // RegisterWrapperProxy // RegisterWrapperProxy::RegisterWrapperProxy( ObjectWrapper::CreateInstanceFunc *createInstanceFunc, const std::string& name, const std::string& associates, AddPropFunc func ) { _wrapper = new ObjectWrapper( createInstanceFunc, name, associates ); if ( func ) (*func)( _wrapper.get() ); if (Registry::instance()) { Registry::instance()->getObjectWrapperManager()->addWrapper( _wrapper.get() ); } } RegisterWrapperProxy::~RegisterWrapperProxy() { if (Registry::instance()) { Registry::instance()->getObjectWrapperManager()->removeWrapper( _wrapper.get() ); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // RegisterCustomWrapperProxy // RegisterCustomWrapperProxy::RegisterCustomWrapperProxy( ObjectWrapper::CreateInstanceFunc *createInstanceFunc, const std::string& domain, const std::string& name, const std::string& associates, AddPropFunc func ) { _wrapper = new ObjectWrapper( createInstanceFunc, domain, name, associates ); if ( func ) (*func)( domain.c_str(), _wrapper.get() ); if (Registry::instance()) { Registry::instance()->getObjectWrapperManager()->addWrapper( _wrapper.get() ); } } RegisterCustomWrapperProxy::~RegisterCustomWrapperProxy() { if (Registry::instance()) { Registry::instance()->getObjectWrapperManager()->removeWrapper( _wrapper.get() ); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // ObjectWrapperManager // //////////////////////////////////////////////////////////////////////////////////////////////////////// // // GlobalLookupTable // ObjectWrapperManager::ObjectWrapperManager() { IntLookup& glTable = _globalMap["GL"]; // Modes glTable.add( "GL_ALPHA_TEST", GL_ALPHA_TEST ); glTable.add( "GL_BLEND", GL_BLEND ); glTable.add( "GL_COLOR_LOGIC_OP", GL_COLOR_LOGIC_OP ); glTable.add( "GL_COLOR_MATERIAL", GL_COLOR_MATERIAL ); glTable.add( "GL_CULL_FACE", GL_CULL_FACE ); glTable.add( "GL_DEPTH_TEST", GL_DEPTH_TEST ); glTable.add( "GL_FOG", GL_FOG ); glTable.add( "GL_FRAGMENT_PROGRAM_ARB", GL_FRAGMENT_PROGRAM_ARB ); glTable.add( "GL_LINE_STIPPLE", GL_LINE_STIPPLE ); glTable.add( "GL_POINT_SMOOTH", GL_POINT_SMOOTH ); glTable.add( "GL_POINT_SPRITE_ARB", GL_POINT_SPRITE_ARB ); glTable.add( "GL_POLYGON_OFFSET_FILL", GL_POLYGON_OFFSET_FILL ); glTable.add( "GL_POLYGON_OFFSET_LINE", GL_POLYGON_OFFSET_LINE ); glTable.add( "GL_POLYGON_OFFSET_POINT", GL_POLYGON_OFFSET_POINT ); glTable.add( "GL_POLYGON_STIPPLE", GL_POLYGON_STIPPLE ); glTable.add( "GL_SCISSOR_TEST", GL_SCISSOR_TEST); glTable.add( "GL_STENCIL_TEST", GL_STENCIL_TEST ); glTable.add( "GL_STENCIL_TEST_TWO_SIDE", GL_STENCIL_TEST_TWO_SIDE ); glTable.add( "GL_VERTEX_PROGRAM_ARB", GL_VERTEX_PROGRAM_ARB ); glTable.add( "GL_COLOR_SUM", GL_COLOR_SUM ); glTable.add( "GL_LIGHTING", GL_LIGHTING ); glTable.add( "GL_NORMALIZE", GL_NORMALIZE ); glTable.add( "GL_RESCALE_NORMAL", GL_RESCALE_NORMAL ); glTable.add( "GL_TEXTURE_1D", GL_TEXTURE_1D ); glTable.add( "GL_TEXTURE_2D", GL_TEXTURE_2D ); glTable.add( "GL_TEXTURE_3D", GL_TEXTURE_3D ); glTable.add( "GL_TEXTURE_CUBE_MAP", GL_TEXTURE_CUBE_MAP ); glTable.add( "GL_TEXTURE_RECTANGLE", GL_TEXTURE_RECTANGLE ); glTable.add( "GL_TEXTURE_GEN_Q", GL_TEXTURE_GEN_Q ); glTable.add( "GL_TEXTURE_GEN_R", GL_TEXTURE_GEN_R ); glTable.add( "GL_TEXTURE_GEN_S", GL_TEXTURE_GEN_S ); glTable.add( "GL_TEXTURE_GEN_T", GL_TEXTURE_GEN_T ); glTable.add( "GL_CLIP_PLANE0", GL_CLIP_PLANE0 ); glTable.add( "GL_CLIP_PLANE1", GL_CLIP_PLANE1 ); glTable.add( "GL_CLIP_PLANE2", GL_CLIP_PLANE2 ); glTable.add( "GL_CLIP_PLANE3", GL_CLIP_PLANE3 ); glTable.add( "GL_CLIP_PLANE4", GL_CLIP_PLANE4 ); glTable.add( "GL_CLIP_PLANE5", GL_CLIP_PLANE5 ); glTable.add( "GL_LIGHT0", GL_LIGHT0 ); glTable.add( "GL_LIGHT1", GL_LIGHT1 ); glTable.add( "GL_LIGHT2", GL_LIGHT2 ); glTable.add( "GL_LIGHT3", GL_LIGHT3 ); glTable.add( "GL_LIGHT4", GL_LIGHT4 ); glTable.add( "GL_LIGHT5", GL_LIGHT5 ); glTable.add( "GL_LIGHT6", GL_LIGHT6 ); glTable.add( "GL_LIGHT7", GL_LIGHT7 ); glTable.add("GL_VERTEX_PROGRAM_POINT_SIZE", GL_VERTEX_PROGRAM_POINT_SIZE); glTable.add("GL_VERTEX_PROGRAM_TWO_SIDE", GL_VERTEX_PROGRAM_TWO_SIDE); // Functions glTable.add( "NEVER", GL_NEVER ); glTable.add( "LESS", GL_LESS ); glTable.add( "EQUAL", GL_EQUAL ); glTable.add( "LEQUAL", GL_LEQUAL ); glTable.add( "GREATER", GL_GREATER ); glTable.add( "NOTEQUAL", GL_NOTEQUAL ); glTable.add( "GEQUAL", GL_GEQUAL ); glTable.add( "ALWAYS", GL_ALWAYS ); // Texture environment states glTable.add( "REPLACE", GL_REPLACE ); glTable.add( "MODULATE", GL_MODULATE ); glTable.add( "ADD", GL_ADD ); glTable.add( "ADD_SIGNED", GL_ADD_SIGNED_ARB ); glTable.add( "INTERPOLATE", GL_INTERPOLATE_ARB ); glTable.add( "SUBTRACT", GL_SUBTRACT_ARB ); glTable.add( "DOT3_RGB", GL_DOT3_RGB_ARB ); glTable.add( "DOT3_RGBA", GL_DOT3_RGBA_ARB ); glTable.add( "CONSTANT", GL_CONSTANT_ARB ); glTable.add( "PRIMARY_COLOR", GL_PRIMARY_COLOR_ARB ); glTable.add( "PREVIOUS", GL_PREVIOUS_ARB ); glTable.add( "TEXTURE", GL_TEXTURE ); glTable.add( "TEXTURE0", GL_TEXTURE0 ); glTable.add( "TEXTURE1", GL_TEXTURE0+1 ); glTable.add( "TEXTURE2", GL_TEXTURE0+2 ); glTable.add( "TEXTURE3", GL_TEXTURE0+3 ); glTable.add( "TEXTURE4", GL_TEXTURE0+4 ); glTable.add( "TEXTURE5", GL_TEXTURE0+5 ); glTable.add( "TEXTURE6", GL_TEXTURE0+6 ); glTable.add( "TEXTURE7", GL_TEXTURE0+7 ); // Texture clamp modes glTable.add( "CLAMP", GL_CLAMP ); glTable.add( "CLAMP_TO_EDGE", GL_CLAMP_TO_EDGE ); glTable.add( "CLAMP_TO_BORDER", GL_CLAMP_TO_BORDER_ARB ); glTable.add( "REPEAT", GL_REPEAT ); glTable.add( "MIRROR", GL_MIRRORED_REPEAT_IBM ); // Texture filter modes glTable.add( "LINEAR", GL_LINEAR ); glTable.add( "LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR ); glTable.add( "LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST ); glTable.add( "NEAREST", GL_NEAREST ); glTable.add( "NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR ); glTable.add( "NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST ); // Texture formats glTable.add( "GL_INTENSITY", GL_INTENSITY ); glTable.add( "GL_LUMINANCE", GL_LUMINANCE ); glTable.add( "GL_ALPHA", GL_ALPHA ); glTable.add( "GL_LUMINANCE_ALPHA", GL_LUMINANCE_ALPHA ); glTable.add( "GL_RGB", GL_RGB ); glTable.add( "GL_RGBA", GL_RGBA ); glTable.add( "GL_COMPRESSED_ALPHA_ARB", GL_COMPRESSED_ALPHA_ARB ); glTable.add( "GL_COMPRESSED_LUMINANCE_ARB", GL_COMPRESSED_LUMINANCE_ARB ); glTable.add( "GL_COMPRESSED_INTENSITY_ARB", GL_COMPRESSED_INTENSITY_ARB ); glTable.add( "GL_COMPRESSED_LUMINANCE_ALPHA_ARB", GL_COMPRESSED_LUMINANCE_ALPHA_ARB ); glTable.add( "GL_COMPRESSED_RGB_ARB", GL_COMPRESSED_RGB_ARB ); glTable.add( "GL_COMPRESSED_RGBA_ARB", GL_COMPRESSED_RGBA_ARB ); glTable.add( "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", GL_COMPRESSED_RGB_S3TC_DXT1_EXT ); glTable.add( "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT", GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ); glTable.add( "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT", GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ); glTable.add( "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT", GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ); glTable.add( "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG",GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG ); glTable.add( "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG",GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG ); glTable.add( "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG",GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ); glTable.add( "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG",GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG ); glTable.add( "GL_ETC1_RGB8_OES",GL_ETC1_RGB8_OES ); glTable.add( "GL_COMPRESSED_RGB8_ETC2",GL_COMPRESSED_RGB8_ETC2 ); glTable.add( "GL_COMPRESSED_SRGB8_ETC2",GL_COMPRESSED_SRGB8_ETC2 ); glTable.add( "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2",GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ); glTable.add( "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2",GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 ); glTable.add( "GL_COMPRESSED_RGBA8_ETC2_EAC",GL_COMPRESSED_RGBA8_ETC2_EAC ); glTable.add( "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC",GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC ); glTable.add( "GL_COMPRESSED_R11_EAC",GL_COMPRESSED_R11_EAC ); glTable.add( "GL_COMPRESSED_SIGNED_R11_EAC",GL_COMPRESSED_SIGNED_R11_EAC ); glTable.add( "GL_COMPRESSED_RG11_EAC",GL_COMPRESSED_RG11_EAC ); glTable.add( "GL_COMPRESSED_SIGNED_RG11_EAC",GL_COMPRESSED_SIGNED_RG11_EAC ); // Texture source types glTable.add( "GL_BYTE", GL_BYTE ); glTable.add( "GL_SHORT", GL_SHORT ); glTable.add( "GL_INT", GL_INT ); glTable.add( "GL_FLOAT", GL_FLOAT ); glTable.add( "GL_DOUBLE", GL_DOUBLE ); glTable.add( "GL_UNSIGNED_BYTE", GL_UNSIGNED_BYTE ); glTable.add( "GL_UNSIGNED_SHORT", GL_UNSIGNED_SHORT ); glTable.add( "GL_UNSIGNED_INT", GL_UNSIGNED_INT ); // Blend values glTable.add( "DST_ALPHA", GL_DST_ALPHA ); glTable.add( "DST_COLOR", GL_DST_COLOR ); glTable.add( "ONE", GL_ONE ); glTable.add( "ONE_MINUS_DST_ALPHA", GL_ONE_MINUS_DST_ALPHA ); glTable.add( "ONE_MINUS_DST_COLOR", GL_ONE_MINUS_DST_COLOR ); glTable.add( "ONE_MINUS_SRC_ALPHA", GL_ONE_MINUS_SRC_ALPHA ); glTable.add( "ONE_MINUS_SRC_COLOR", GL_ONE_MINUS_SRC_COLOR ); glTable.add( "SRC_ALPHA", GL_SRC_ALPHA ); glTable.add( "SRC_ALPHA_SATURATE", GL_SRC_ALPHA_SATURATE ); glTable.add( "SRC_COLOR", GL_SRC_COLOR ); glTable.add( "CONSTANT_COLOR", GL_CONSTANT_COLOR ); glTable.add( "ONE_MINUS_CONSTANT_COLOR", GL_ONE_MINUS_CONSTANT_COLOR ); glTable.add( "CONSTANT_ALPHA", GL_CONSTANT_ALPHA ); glTable.add( "ONE_MINUS_CONSTANT_ALPHA", GL_ONE_MINUS_CONSTANT_ALPHA ); glTable.add( "ZERO", GL_ZERO ); // Fog coordinate sources glTable.add( "COORDINATE", GL_FOG_COORDINATE ); glTable.add( "DEPTH", GL_FRAGMENT_DEPTH ); // Hint targets glTable.add( "FOG_HINT", GL_FOG_HINT ); glTable.add( "GENERATE_MIPMAP_HINT", GL_GENERATE_MIPMAP_HINT_SGIS ); glTable.add( "LINE_SMOOTH_HINT", GL_LINE_SMOOTH_HINT ); glTable.add( "PERSPECTIVE_CORRECTION_HINT", GL_PERSPECTIVE_CORRECTION_HINT ); glTable.add( "POINT_SMOOTH_HINT", GL_POINT_SMOOTH_HINT ); glTable.add( "POLYGON_SMOOTH_HINT", GL_POLYGON_SMOOTH_HINT ); glTable.add( "TEXTURE_COMPRESSION_HINT", GL_TEXTURE_COMPRESSION_HINT_ARB ); glTable.add( "FRAGMENT_SHADER_DERIVATIVE_HINT", GL_FRAGMENT_SHADER_DERIVATIVE_HINT ); // Polygon modes glTable.add( "POINT", GL_POINT ); glTable.add( "LINE", GL_LINE ); glTable.add( "FILL", GL_FILL ); // Misc glTable.add( "BACK", GL_BACK ); glTable.add( "FRONT", GL_FRONT ); glTable.add( "FRONT_AND_BACK", GL_FRONT_AND_BACK ); glTable.add( "FIXED_ONLY", GL_FIXED_ONLY ); glTable.add( "FASTEST", GL_FASTEST ); glTable.add( "NICEST", GL_NICEST ); glTable.add( "DONT_CARE", GL_DONT_CARE ); IntLookup& arrayTable = _globalMap["ArrayType"]; arrayTable.add( "ByteArray", ID_BYTE_ARRAY ); arrayTable.add( "UByteArray", ID_UBYTE_ARRAY ); arrayTable.add( "ShortArray", ID_SHORT_ARRAY ); arrayTable.add( "UShortArray", ID_USHORT_ARRAY ); arrayTable.add( "IntArray", ID_INT_ARRAY ); arrayTable.add( "UIntArray", ID_UINT_ARRAY ); arrayTable.add( "FloatArray", ID_FLOAT_ARRAY ); arrayTable.add( "DoubleArray", ID_DOUBLE_ARRAY ); arrayTable.add( "Vec2bArray", ID_VEC2B_ARRAY ); arrayTable.add( "Vec3bArray", ID_VEC3B_ARRAY ); arrayTable.add( "Vec4bArray", ID_VEC4B_ARRAY ); arrayTable.add( "Vec2ubArray", ID_VEC2UB_ARRAY ); arrayTable.add( "Vec3ubArray", ID_VEC3UB_ARRAY ); arrayTable.add( "Vec4ubArray", ID_VEC4UB_ARRAY ); arrayTable.add( "Vec2sArray", ID_VEC2S_ARRAY ); arrayTable.add( "Vec3sArray", ID_VEC3S_ARRAY ); arrayTable.add( "Vec4sArray", ID_VEC4S_ARRAY ); arrayTable.add( "Vec2usArray", ID_VEC2US_ARRAY ); arrayTable.add( "Vec3usArray", ID_VEC3US_ARRAY ); arrayTable.add( "Vec4usArray", ID_VEC4US_ARRAY ); arrayTable.add( "Vec2fArray", ID_VEC2_ARRAY ); arrayTable.add( "Vec3fArray", ID_VEC3_ARRAY ); arrayTable.add( "Vec4fArray", ID_VEC4_ARRAY ); arrayTable.add( "Vec2dArray", ID_VEC2D_ARRAY ); arrayTable.add( "Vec3dArray", ID_VEC3D_ARRAY ); arrayTable.add( "Vec4dArray", ID_VEC4D_ARRAY ); arrayTable.add( "Vec2iArray", ID_VEC2I_ARRAY ); arrayTable.add( "Vec3iArray", ID_VEC3I_ARRAY ); arrayTable.add( "Vec4iArray", ID_VEC4I_ARRAY ); arrayTable.add( "Vec2uiArray", ID_VEC2UI_ARRAY ); arrayTable.add( "Vec3uiArray", ID_VEC3UI_ARRAY ); arrayTable.add( "Vec4uiArray", ID_VEC4UI_ARRAY ); IntLookup& primitiveTable = _globalMap["PrimitiveType"]; primitiveTable.add( "DrawArrays", ID_DRAWARRAYS ); primitiveTable.add( "DrawArraysLength", ID_DRAWARRAY_LENGTH ); primitiveTable.add( "DrawElementsUByte", ID_DRAWELEMENTS_UBYTE ); primitiveTable.add( "DrawElementsUShort", ID_DRAWELEMENTS_USHORT ); primitiveTable.add( "DrawElementsUInt", ID_DRAWELEMENTS_UINT ); primitiveTable.add( "GL_POINTS", GL_POINTS ); primitiveTable.add( "GL_LINES", GL_LINES ); primitiveTable.add( "GL_LINE_STRIP", GL_LINE_STRIP ); primitiveTable.add( "GL_LINE_LOOP", GL_LINE_LOOP ); primitiveTable.add( "GL_TRIANGLES", GL_TRIANGLES ); primitiveTable.add( "GL_TRIANGLE_STRIP", GL_TRIANGLE_STRIP ); primitiveTable.add( "GL_TRIANGLE_FAN", GL_TRIANGLE_FAN ); primitiveTable.add( "GL_QUADS", GL_QUADS ); primitiveTable.add( "GL_QUAD_STRIP", GL_QUAD_STRIP ); primitiveTable.add( "GL_POLYGON", GL_POLYGON ); primitiveTable.add( "GL_LINES_ADJACENCY_EXT", GL_LINES_ADJACENCY_EXT ); primitiveTable.add( "GL_LINE_STRIP_ADJACENCY_EXT", GL_LINE_STRIP_ADJACENCY_EXT ); primitiveTable.add( "GL_TRIANGLES_ADJACENCY_EXT", GL_TRIANGLES_ADJACENCY_EXT ); primitiveTable.add( "GL_TRIANGLE_STRIP_ADJACENCY_EXT", GL_TRIANGLE_STRIP_ADJACENCY_EXT ); primitiveTable.add( "GL_LINES_ADJACENCY", GL_LINES_ADJACENCY ); primitiveTable.add( "GL_LINE_STRIP_ADJACENCY", GL_LINE_STRIP_ADJACENCY ); primitiveTable.add( "GL_TRIANGLES_ADJACENCY", GL_TRIANGLES_ADJACENCY ); primitiveTable.add( "GL_TRIANGLE_STRIP_ADJACENCY", GL_TRIANGLE_STRIP_ADJACENCY ); primitiveTable.add( "GL_PATCHES", GL_PATCHES ); } ObjectWrapperManager::~ObjectWrapperManager() { } void ObjectWrapperManager::addWrapper( ObjectWrapper* wrapper ) { if ( !wrapper ) return; OpenThreads::ScopedLock lock(_wrapperMutex); WrapperMap::iterator itr = _wrappers.find( wrapper->getName() ); if ( itr!=_wrappers.end() ) { OSG_WARN << "ObjectWrapperManager::addWrapper(): '" << wrapper->getName() << "' already exists." << std::endl; } _wrappers[wrapper->getName()] = wrapper; } void ObjectWrapperManager::removeWrapper( ObjectWrapper* wrapper ) { if ( !wrapper ) return; OpenThreads::ScopedLock lock(_wrapperMutex); WrapperMap::iterator itr = _wrappers.find( wrapper->getName() ); if ( itr!=_wrappers.end() ) _wrappers.erase( itr ); } ObjectWrapper* ObjectWrapperManager::findWrapper( const std::string& name ) { OpenThreads::ScopedLock lock(_wrapperMutex); WrapperMap::iterator itr = _wrappers.find( name ); if ( itr!=_wrappers.end() ) return itr->second.get(); // Load external libraries std::string::size_type posDoubleColon = name.rfind("::"); if ( posDoubleColon!=std::string::npos ) { std::string libName = std::string( name, 0, posDoubleColon ); std::string nodeKitLib = osgDB::Registry::instance()->createLibraryNameForNodeKit(libName); if ( osgDB::Registry::instance()->loadLibrary(nodeKitLib)==osgDB::Registry::LOADED ) return findWrapper(name); std::string pluginLib = osgDB::Registry::instance()->createLibraryNameForExtension(std::string("serializers_")+libName); if ( osgDB::Registry::instance()->loadLibrary(pluginLib)==osgDB::Registry::LOADED ) return findWrapper(name); pluginLib = osgDB::Registry::instance()->createLibraryNameForExtension(libName); if ( osgDB::Registry::instance()->loadLibrary(pluginLib)==osgDB::Registry::LOADED ) return findWrapper(name); } return NULL; } void ObjectWrapperManager::addCompressor( BaseCompressor* compressor ) { if ( !compressor ) return; OpenThreads::ScopedLock lock(_wrapperMutex); CompressorMap::iterator itr = _compressors.find( compressor->getName() ); if ( itr!=_compressors.end() ) { OSG_WARN << "ObjectWrapperManager::addCompressor(): '" << compressor->getName() << "' already exists." << std::endl; } _compressors[compressor->getName()] = compressor; } void ObjectWrapperManager::removeCompressor( BaseCompressor* compressor ) { if ( !compressor ) return; OpenThreads::ScopedLock lock(_wrapperMutex); CompressorMap::iterator itr = _compressors.find( compressor->getName() ); if ( itr!=_compressors.end() ) _compressors.erase( itr ); } BaseCompressor* ObjectWrapperManager::findCompressor( const std::string& name ) { OpenThreads::ScopedLock lock(_wrapperMutex); CompressorMap::iterator itr = _compressors.find( name ); if ( itr!=_compressors.end() ) return itr->second.get(); // Load external libraries std::string nodeKitLib = osgDB::Registry::instance()->createLibraryNameForNodeKit(name); if ( osgDB::Registry::instance()->loadLibrary(nodeKitLib)==osgDB::Registry::LOADED ) return findCompressor(name); std::string pluginLib = osgDB::Registry::instance()->createLibraryNameForExtension(std::string("compressor_")+name); if ( osgDB::Registry::instance()->loadLibrary(pluginLib)==osgDB::Registry::LOADED ) return findCompressor(name); pluginLib = osgDB::Registry::instance()->createLibraryNameForExtension(name); if ( osgDB::Registry::instance()->loadLibrary(pluginLib)==osgDB::Registry::LOADED ) return findCompressor(name); return NULL; } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // RegisytrCompressorProxy // RegisterCompressorProxy::RegisterCompressorProxy( const std::string& name, BaseCompressor* compressor ): _compressor(compressor) { _compressor->setName( name ); if (Registry::instance()) { Registry::instance()->getObjectWrapperManager()->addCompressor( _compressor.get() ); } } RegisterCompressorProxy::~RegisterCompressorProxy() { if (Registry::instance()) { Registry::instance()->getObjectWrapperManager()->removeCompressor( _compressor.get() ); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/Callbacks.cpp0000644000175000017500000001071213151044751023233 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgDB; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // FindFileCallback default implementation // std::string FindFileCallback::findDataFile(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity) { return osgDB::Registry::instance()->findDataFileImplementation(filename, options, caseSensitivity); } std::string FindFileCallback::findLibraryFile(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity) { return osgDB::Registry::instance()->findLibraryFileImplementation(filename, options, caseSensitivity); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ReadFileCallback default implementation // ReaderWriter::ReadResult ReadFileCallback::openArchive(const std::string& filename,ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* useObjectCache) { return osgDB::Registry::instance()->openArchiveImplementation(filename, status, indexBlockSizeHint, useObjectCache); } ReaderWriter::ReadResult ReadFileCallback::readObject(const std::string& filename, const Options* options) { return osgDB::Registry::instance()->readObjectImplementation(filename,options); } ReaderWriter::ReadResult ReadFileCallback::readImage(const std::string& filename, const Options* options) { return osgDB::Registry::instance()->readImageImplementation(filename,options); } ReaderWriter::ReadResult ReadFileCallback::readHeightField(const std::string& filename, const Options* options) { return osgDB::Registry::instance()->readHeightFieldImplementation(filename,options); } ReaderWriter::ReadResult ReadFileCallback::readNode(const std::string& filename, const Options* options) { return osgDB::Registry::instance()->readNodeImplementation(filename,options); } ReaderWriter::ReadResult ReadFileCallback::readShader(const std::string& filename, const Options* options) { return osgDB::Registry::instance()->readShaderImplementation(filename,options); } ReaderWriter::ReadResult ReadFileCallback::readScript(const std::string& filename, const Options* options) { return osgDB::Registry::instance()->readScriptImplementation(filename,options); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // WriteFileCallback default implementation // ReaderWriter::WriteResult WriteFileCallback::writeObject(const osg::Object& obj, const std::string& fileName,const Options* options) { return osgDB::Registry::instance()->writeObjectImplementation(obj,fileName,options); } ReaderWriter::WriteResult WriteFileCallback::writeImage(const osg::Image& obj, const std::string& fileName,const Options* options) { return osgDB::Registry::instance()->writeImageImplementation(obj,fileName,options); } ReaderWriter::WriteResult WriteFileCallback::writeHeightField(const osg::HeightField& obj, const std::string& fileName,const Options* options) { return osgDB::Registry::instance()->writeHeightFieldImplementation(obj,fileName,options); } ReaderWriter::WriteResult WriteFileCallback::writeNode(const osg::Node& obj, const std::string& fileName,const Options* options) { return osgDB::Registry::instance()->writeNodeImplementation(obj,fileName,options); } ReaderWriter::WriteResult WriteFileCallback::writeShader(const osg::Shader& obj, const std::string& fileName,const Options* options) { return osgDB::Registry::instance()->writeShaderImplementation(obj,fileName,options); } ReaderWriter::WriteResult WriteFileCallback::writeScript(const osg::Script& obj, const std::string& fileName,const Options* options) { return osgDB::Registry::instance()->writeScriptImplementation(obj,fileName,options); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/WriteFile.cpp0000644000175000017500000000550313151044751023250 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include using namespace osg; using namespace osgDB; bool osgDB::writeObjectFile(const Object& object,const std::string& filename, const Options* options ) { ReaderWriter::WriteResult wr = Registry::instance()->writeObject( object, filename, options ); if (wr.error()) OSG_WARN << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } bool osgDB::writeImageFile(const Image& image,const std::string& filename, const Options* options ) { ReaderWriter::WriteResult wr = Registry::instance()->writeImage( image, filename, options ); if (wr.error()) OSG_WARN << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } bool osgDB::writeHeightFieldFile(const HeightField& HeightField,const std::string& filename, const Options* options ) { ReaderWriter::WriteResult wr = Registry::instance()->writeHeightField( HeightField, filename, options ); if (wr.error()) OSG_WARN << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } bool osgDB::writeNodeFile(const Node& node,const std::string& filename, const Options* options ) { ReaderWriter::WriteResult wr = Registry::instance()->writeNode( node, filename, options ); if (wr.error()) OSG_WARN << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } bool osgDB::writeShaderFile(const Shader& shader,const std::string& filename, const Options* options ) { ReaderWriter::WriteResult wr = Registry::instance()->writeShader( shader, filename, options ); if (wr.error()) OSG_WARN << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } bool osgDB::writeScriptFile(const Script& image,const std::string& filename, const Options* options ) { ReaderWriter::WriteResult wr = Registry::instance()->writeScript( image, filename, options ); if (wr.error()) OSG_WARN << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/FieldReader.cpp0000644000175000017500000002036213151044751023524 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osgDB; FieldReader::FieldReader() { _init(); } FieldReader::FieldReader(const FieldReader& ic) { _copy(ic); } FieldReader::~FieldReader() { _free(); } FieldReader& FieldReader::operator = (const FieldReader& ic) { if (this==&ic) return *this; _free(); _copy(ic); return *this; } void FieldReader::_free() { // free all data _init(); } void FieldReader::_init() { _fin = NULL; _eof = true; _noNestedBrackets = 0; int i; for(i=0;i<256;++i) _delimiterEatLookUp[i]=false; _delimiterEatLookUp[int(' ')] = true; _delimiterEatLookUp[int('\t')] = true; _delimiterEatLookUp[int('\n')] = true; _delimiterEatLookUp[int('\r')] = true; for(i=0;i<256;++i) _delimiterKeepLookUp[i]=false; _delimiterKeepLookUp[int('{')] = true; _delimiterKeepLookUp[int('}')] = true; _delimiterKeepLookUp[int('"')] = true; _delimiterKeepLookUp[int('\'')] = true; } void FieldReader::_copy(const FieldReader& ic) { _fin = ic._fin; _eof = ic._eof; _noNestedBrackets = ic._noNestedBrackets; int i; for(i=0;i<256;++i) _delimiterEatLookUp[i]=ic._delimiterEatLookUp[i]; for(i=0;i<256;++i) _delimiterKeepLookUp[i]=ic._delimiterKeepLookUp[i]; } void FieldReader::attach(std::istream* input) { _fin = input; if (_fin) { _eof = _fin->eof()!=0; } else { _eof = true; } } void FieldReader::detach() { _fin = NULL; _eof = true; } bool FieldReader::eof() const { return _eof; } bool FieldReader::findStartOfNextField() { int ch = 0; while (true) { ch = _fin->peek(); if (ch==EOF) { _eof = true; return false; } else if (_delimiterEatLookUp[ch]) { _fin->ignore(1); } else { return true; } } } bool FieldReader::readField(Field& fieldPtr) { return _readField(&fieldPtr); } void FieldReader::ignoreField() { _readField(NULL); } bool FieldReader::_readField(Field* fieldPtr) { if (fieldPtr) fieldPtr->reset(); if (!eof() && findStartOfNextField()) { int ch = _fin->peek(); if (ch==EOF) { _eof = true; if (fieldPtr) fieldPtr->setNoNestedBrackets(getNoNestedBrackets()); return fieldPtr && fieldPtr->getNoCharacters()!=0; } else if (ch=='"') { if (fieldPtr) { fieldPtr->setWithinQuotes(true); fieldPtr->setNoNestedBrackets(getNoNestedBrackets()); } _fin->ignore(1); char c; bool escape = false; // use the escape character sequence \" to allow " to included in strings. while (true) { ch = _fin->peek(); if (ch==EOF) { _eof = true; return fieldPtr && fieldPtr->getNoCharacters()!=0; } c = ch; if (ch=='\\') { if (escape) { escape = false; _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } else { escape = true; _fin->ignore(1); } } else if (ch=='"') { if (escape) { escape = false; _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } else { _fin->ignore(1); //return fieldPtr && fieldPtr->getNoCharacters()!=0; return fieldPtr!=NULL; } } else { if (escape) { escape = false; if (fieldPtr) fieldPtr->addChar('\\'); } _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } } } else if (ch=='\'') { if (fieldPtr) { fieldPtr->setWithinQuotes(true); fieldPtr->setNoNestedBrackets(getNoNestedBrackets()); } _fin->ignore(1); char c; bool escape = false; // use the escape character sequence \' to allow ' to included in strings. while (true) { ch = _fin->peek(); if (ch==EOF) { _eof = true; return fieldPtr && fieldPtr->getNoCharacters()!=0; } c = ch; if (ch=='\\' && !escape) { if (escape) { escape = false; _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } else { escape = true; _fin->ignore(1); } } else if (ch=='\'') { if (escape) { escape = false; _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } else { _fin->ignore(1); //return fieldPtr && fieldPtr->getNoCharacters()!=0; return fieldPtr!=NULL; } } else { if (escape) { escape = false; if (fieldPtr) fieldPtr->addChar('\\'); } _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } } } else if (_delimiterKeepLookUp[ch]) { char c; _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); if (c=='{') ++_noNestedBrackets; else if (c=='}') --_noNestedBrackets; if (fieldPtr) fieldPtr->setNoNestedBrackets(getNoNestedBrackets()); return fieldPtr && fieldPtr->getNoCharacters()!=0; } else { if (fieldPtr) fieldPtr->setNoNestedBrackets(getNoNestedBrackets()); char c; while (true) { ch = _fin->peek(); if (ch==EOF) { _eof = true; return fieldPtr && fieldPtr->getNoCharacters()!=0; } c = ch; if (_delimiterEatLookUp[int(c)]) { _fin->ignore(1); return fieldPtr && fieldPtr->getNoCharacters()!=0; } if (_delimiterKeepLookUp[int(c)]) { return fieldPtr && fieldPtr->getNoCharacters()!=0; } else { _fin->get(c); if (fieldPtr) fieldPtr->addChar(c); } } } } else { return false; } } int FieldReader::getNoNestedBrackets() const { return _noNestedBrackets; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/DotOsgWrapper.cpp0000644000175000017500000006113313151044751024117 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgDB; DotOsgWrapper::DotOsgWrapper(osg::Object* proto, const std::string& name, const std::string& associates, ReadFunc readFunc, WriteFunc writeFunc, ReadWriteMode readWriteMode) { _prototype = proto; _name = name; // copy the names in the space delimited associates input into // a vector of separated names. std::string::size_type start_of_name = associates.find_first_not_of(' '); while (start_of_name!=std::string::npos) { std::string::size_type end_of_name = associates.find_first_of(' ',start_of_name); if (end_of_name!=std::string::npos) { _associates.push_back(std::string(associates,start_of_name,end_of_name-start_of_name)); start_of_name = associates.find_first_not_of(' ',end_of_name); } else { _associates.push_back(std::string(associates,start_of_name,associates.size()-start_of_name)); start_of_name = end_of_name; } } _readFunc = readFunc; _writeFunc = writeFunc; _readWriteMode = readWriteMode; } RegisterDotOsgWrapperProxy::RegisterDotOsgWrapperProxy(osg::Object* proto, const std::string& name, const std::string& associates, DotOsgWrapper::ReadFunc readFunc, DotOsgWrapper::WriteFunc writeFunc, DotOsgWrapper::ReadWriteMode readWriteMode) { if (Registry::instance()) { _wrapper = new DotOsgWrapper(proto,name,associates,readFunc,writeFunc,readWriteMode); Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->addDotOsgWrapper(_wrapper.get()); } } RegisterDotOsgWrapperProxy::~RegisterDotOsgWrapperProxy() { if (Registry::instance()) { Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->removeDotOsgWrapper(_wrapper.get()); } } void DeprecatedDotOsgWrapperManager::addDotOsgWrapper(DotOsgWrapper* wrapper) { if (wrapper==0L) return; //OSG_INFO << "osg::Registry::addDotOsgWrapper("<getName()<<")"<< std::endl; const DotOsgWrapper::Associates& assoc = wrapper->getAssociates(); for(DotOsgWrapper::Associates::const_iterator itr=assoc.begin(); itr!=assoc.end(); ++itr) { //OSG_INFO << " ("<<*itr<<")"<< std::endl; } const std::string& name = wrapper->getName(); const osg::Object* proto = wrapper->getPrototype(); _objectWrapperMap[name] = wrapper; if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[name] = wrapper; if (proto) { std::string libraryName = proto->libraryName(); std::string compositeName = libraryName + "::" + name; _objectWrapperMap[compositeName] = wrapper; if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[compositeName] = wrapper; if (dynamic_cast(proto)) { _imageWrapperMap[name] = wrapper; _imageWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _drawableWrapperMap[name] = wrapper; _drawableWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _stateAttrWrapperMap[name] = wrapper; _stateAttrWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _uniformWrapperMap[name] = wrapper; _uniformWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _nodeWrapperMap[name] = wrapper; _nodeWrapperMap[compositeName] = wrapper; } if (dynamic_cast(proto)) { _shaderWrapperMap[name] = wrapper; _shaderWrapperMap[compositeName] = wrapper; } } } // need to change to delete all instances of wrapper, since we // now can have a wrapper entered twice with the addition of the // library::class composite name. void DeprecatedDotOsgWrapperManager::eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper) { typedef std::vector EraseList; EraseList eraseList; for(DotOsgWrapperMap::iterator witr=wrappermap.begin(); witr!=wrappermap.end(); ++witr) { if (witr->second==wrapper) eraseList.push_back(witr); } for(EraseList::iterator eitr=eraseList.begin(); eitr!=eraseList.end(); ++eitr) { wrappermap.erase(*eitr); } } void DeprecatedDotOsgWrapperManager::removeDotOsgWrapper(DotOsgWrapper* wrapper) { if (wrapper==0L) return; eraseWrapper(_objectWrapperMap,wrapper); eraseWrapper(_classNameWrapperMap,wrapper); eraseWrapper(_imageWrapperMap,wrapper); eraseWrapper(_drawableWrapperMap,wrapper); eraseWrapper(_uniformWrapperMap,wrapper); eraseWrapper(_stateAttrWrapperMap,wrapper); eraseWrapper(_nodeWrapperMap,wrapper); eraseWrapper(_shaderWrapperMap,wrapper); } struct concrete_wrapper: basic_type_wrapper { virtual ~concrete_wrapper() {} concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {} bool matches(const osg::Object *proto) const { return myobj_->isSameKindAs(proto); } const osg::Object *myobj_; }; osg::Object* DeprecatedDotOsgWrapperManager::readObjectOfType(const osg::Object& compObj,Input& fr) { return readObjectOfType(concrete_wrapper(&compObj), fr); } bool DeprecatedDotOsgWrapperManager::getLibraryFileNamesToTry(const std::string& name, FileNames& fileNames) { FileNames::size_type sizeBefore = fileNames.size(); std::string libraryName = osgDB::Registry::instance()->createLibraryNameForNodeKit(name); if (!libraryName.empty()) fileNames.push_back(libraryName); libraryName = osgDB::Registry::instance()->createLibraryNameForExtension(std::string("deprecated_")+name); if (!libraryName.empty()) fileNames.push_back(libraryName); libraryName = osgDB::Registry::instance()->createLibraryNameForExtension(name); if (!libraryName.empty()) fileNames.push_back(libraryName); return fileNames.size() != sizeBefore; } osg::Object* DeprecatedDotOsgWrapperManager::readObjectOfType(const basic_type_wrapper &btw,Input& fr) { const char *str = fr[0].getStr(); if (str==NULL) return NULL; if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Object* obj = fr.getObjectForUniqueID(fr[1].getStr()); if (obj && btw.matches(obj)) { fr+=2; return obj; } } else return NULL; } std::string name = str; DotOsgWrapperMap::iterator itr = _objectWrapperMap.find(name); if (itr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = fr[0].getStr(); std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the readObject to see // if we can recognize the objects. std::string libraryName = std::string(token,0,posDoubleColon); FileNames fileNames; if (getLibraryFileNamesToTry(libraryName, fileNames)) { for(FileNames::iterator itr = fileNames.begin(); itr != fileNames.end(); ++itr) { if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) return readObjectOfType(btw,fr); } } } } else if (fr[1].isOpenBracket()) { DotOsgWrapper* wrapper = itr->second.get(); const osg::Object* proto = wrapper->getPrototype(); if (proto==NULL) { OSG_WARN<<"Token "<getAssociates(); osg::Object* obj = proto->cloneType(); while(!fr.eof() && fr[0].getNoNestedBrackets()>entry) { bool iteratorAdvanced = false; if (fr[0].matchWord("UniqueID") && fr[1].isString()) { fr.registerUniqueIDForObject(fr[1].getStr(),obj); fr += 2; iteratorAdvanced = true; } // read the local data by iterating through the associate // list, mapping the associate names to DotOsgWrapper's which // in turn have the appropriate functions. for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin(); aitr!=assoc.end(); ++aitr) { DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr); if (mitr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = *aitr; std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // and try to load it, and then retry the find to see // if we can recognize the objects. std::string libraryName = std::string(token,0,posDoubleColon); FileNames fileNames; if (getLibraryFileNamesToTry(libraryName, fileNames)) { for(FileNames::iterator itr = fileNames.begin(); itr != fileNames.end() && mitr==_objectWrapperMap.end(); ++itr) { if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) { mitr = _objectWrapperMap.find(*aitr); } } } } } if (mitr!=_objectWrapperMap.end()) { // get the function to read the data... DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc(); if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true; } } if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock(); } ++fr; // step over trailing '}' return obj; } return 0L; } // // read object from input iterator. // osg::Object* DeprecatedDotOsgWrapperManager::readObject(DotOsgWrapperMap& dowMap,Input& fr) { const char *str = fr[0].getStr(); if (str==NULL) return NULL; std::string name = str; DotOsgWrapperMap::iterator itr = dowMap.find(name); if (itr==dowMap.end()) { // not found so check if a library::class composite name. std::string token = fr[0].getStr(); std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the readObject to see // if we can recognize the objects. std::string libraryName = std::string(token,0,posDoubleColon); FileNames fileNames; if (getLibraryFileNamesToTry(libraryName, fileNames)) { for(FileNames::iterator itr = fileNames.begin(); itr != fileNames.end(); ++itr) { if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) return readObject(dowMap,fr); } } } } else if (fr[1].isOpenBracket()) { DotOsgWrapper* wrapper = itr->second.get(); const osg::Object* proto = wrapper->getPrototype(); if (proto==NULL) { OSG_WARN<<"Token "<getAssociates(); osg::Object* obj = proto->cloneType(); while(!fr.eof() && fr[0].getNoNestedBrackets()>entry) { bool iteratorAdvanced = false; if (fr[0].matchWord("UniqueID") && fr[1].isString()) { fr.registerUniqueIDForObject(fr[1].getStr(),obj); fr += 2; iteratorAdvanced = true; } // read the local data by iterating through the associate // list, mapping the associate names to DotOsgWrapper's which // in turn have the appropriate functions. for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin(); aitr!=assoc.end(); ++aitr) { DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr); if (mitr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = *aitr; std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the find to see // if we can recognize the objects. std::string libraryName = std::string(token,0,posDoubleColon); FileNames fileNames; if (getLibraryFileNamesToTry(libraryName, fileNames)) { for(FileNames::iterator itr = fileNames.begin(); itr != fileNames.end() && mitr==_objectWrapperMap.end(); ++itr) { if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) { mitr = _objectWrapperMap.find(*aitr); } } } } } if (mitr!=_objectWrapperMap.end()) { // get the function to read the data... DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc(); if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true; } } if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock(); } ++fr; // step over trailing '}' return obj; } return 0L; } // // read object from input iterator. // osg::Object* DeprecatedDotOsgWrapperManager::readObject(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Object* obj = fr.getObjectForUniqueID(fr[1].getStr()); if (obj) fr+=2; return obj; } else return NULL; } return readObject(_objectWrapperMap,fr); } // // read image from input iterator. // osg::Image* DeprecatedDotOsgWrapperManager::readImage(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Image* image = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (image) fr+=2; return image; } else return NULL; } osg::Object* obj = readObject(_imageWrapperMap,fr); osg::Image* image = dynamic_cast(obj); if (image) return image; else if (obj) obj->unref(); return NULL; } // // read drawable from input iterator. // osg::Drawable* DeprecatedDotOsgWrapperManager::readDrawable(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Drawable* drawable = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (drawable) fr+=2; return drawable; } else return NULL; } osg::Object* obj = readObject(_drawableWrapperMap,fr); osg::Drawable* drawable = dynamic_cast(obj); if (drawable) return drawable; else if (obj) obj->unref(); return NULL; } // // read drawable from input iterator. // osg::StateAttribute* DeprecatedDotOsgWrapperManager::readStateAttribute(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::StateAttribute* attribute = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (attribute) fr+=2; return attribute; } else return NULL; } return dynamic_cast(readObject(_stateAttrWrapperMap,fr)); } // // read drawable from input iterator. // osg::Uniform* DeprecatedDotOsgWrapperManager::readUniform(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Uniform* attribute = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (attribute) fr+=2; return attribute; } else return NULL; } return dynamic_cast(readObject(_uniformWrapperMap,fr)); } // // read node from input iterator. // osg::Node* DeprecatedDotOsgWrapperManager::readNode(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Node* node = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (node) fr+=2; return node; } else return NULL; } osg::Object* obj = readObject(_nodeWrapperMap,fr); osg::Node* node = dynamic_cast(obj); if (node) return node; else if (obj) obj->unref(); return NULL; } // // read image from input iterator. // osg::Shader* DeprecatedDotOsgWrapperManager::readShader(Input& fr) { if (fr[0].matchWord("Use")) { if (fr[1].isString()) { osg::Shader* shader = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); if (shader) fr+=2; return shader; } else return NULL; } osg::Object* obj = readObject(_shaderWrapperMap,fr); osg::Shader* shader = dynamic_cast(obj); if (shader) return shader; else if (obj) obj->unref(); return NULL; } // // Write object to output // bool DeprecatedDotOsgWrapperManager::writeObject(const osg::Object& obj,Output& fw) { if (obj.referenceCount()>1) { std::string uniqueID; if (fw.getUniqueIDForObject(&obj,uniqueID)) { fw.writeUseID( uniqueID ); return true; } } const std::string classname( obj.className() ); const std::string libraryName( obj.libraryName() ); const std::string compositeName( libraryName + "::" + classname ); // try composite name first DotOsgWrapperMap::iterator itr = _classNameWrapperMap.find(compositeName); if (itr==_classNameWrapperMap.end()) { FileNames fileNames; if (getLibraryFileNamesToTry(libraryName, fileNames)) { for(FileNames::iterator itr = fileNames.begin(); itr != fileNames.end(); ++itr) { if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) return writeObject(obj,fw); } } // otherwise try simple class name if (itr == _classNameWrapperMap.end()) itr = _classNameWrapperMap.find(classname); } if (itr!=_classNameWrapperMap.end()) { DotOsgWrapper* wrapper = itr->second.get(); const DotOsgWrapper::Associates& assoc = wrapper->getAssociates(); if (libraryName=="osg") { // member of the core osg, so no need to have composite library::class name. fw.writeBeginObject( wrapper->getName() ); } else { // member of the node kit so must use composite library::class name. std::string::size_type posDoubleColon = wrapper->getName().find("::"); if (posDoubleColon != std::string::npos) { fw.writeBeginObject( wrapper->getName() ); } else { fw.writeBeginObject( libraryName + "::" + wrapper->getName() ); } } fw.moveIn(); // write out the unique ID if required. if (obj.referenceCount()>1) { std::string uniqueID; fw.createUniqueIDForObject(&obj,uniqueID); fw.registerUniqueIDForObject(&obj,uniqueID); fw.writeUniqueID( uniqueID ); } // read the local data by iterating through the associate // list, mapping the associate names to DotOsgWrapper's which // in turn have the appropriate functions. for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin(); aitr!=assoc.end(); ++aitr) { DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr); if (mitr==_objectWrapperMap.end()) { // not found so check if a library::class composite name. std::string token = *aitr; std::string::size_type posDoubleColon = token.rfind("::"); if (posDoubleColon != std::string::npos) { // we have a composite name so now strip off the library name // are try to load it, and then retry the find to see // if we can recognize the objects. std::string libraryName = std::string(token,0,posDoubleColon); FileNames fileNames; if (getLibraryFileNamesToTry(libraryName, fileNames)) { for(FileNames::iterator itr = fileNames.begin(); itr != fileNames.end() && mitr==_objectWrapperMap.end(); ++itr) { if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) { mitr = _objectWrapperMap.find(*aitr); } } } } } if (mitr!=_objectWrapperMap.end()) { // get the function to read the data... DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc(); if (wf) (*wf)(obj,fw); } } fw.moveOut(); fw.writeEndObject(); return true; } return false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgDB/XmlParser.cpp0000644000175000017500000003673613151044751023307 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osgDB; XmlNode* osgDB::readXmlFile(const std::string& filename,const Options* options) { std::string foundFile = osgDB::findDataFile(filename, options); if (!foundFile.empty()) { XmlNode::Input input; input.open(foundFile); input.readAllDataIntoBuffer(); if (!input) { OSG_NOTICE<<"Could not open XML file: "< root = new XmlNode; root->read(input); return root.release(); } else { OSG_NOTICE<<"Could not find XML file: "< root = new XmlNode; root->read(input); return root.release(); } XmlNode::ControlMap::ControlMap() { setUpControlMappings(); } void XmlNode::ControlMap::addControlToCharacter(const std::string& control, int c) { _controlToCharacterMap[control] = c; _characterToControlMap[c] = control; } void XmlNode::ControlMap::setUpControlMappings() { addControlToCharacter("&",'&'); addControlToCharacter("<",'<'); addControlToCharacter(">",'>'); addControlToCharacter(""",'"'); addControlToCharacter("'",'\''); } XmlNode::Input::Input(): _currentPos(0) { } XmlNode::Input::Input(const Input&): ControlMap(), _currentPos(0) { } XmlNode::Input::~Input() { } void XmlNode::Input::open(const std::string& filename) { _fin.open(filename.c_str()); } void XmlNode::Input::attach(std::istream& fin) { std::ios &fios = _fin; fios.rdbuf(fin.rdbuf()); } void XmlNode::Input::readAllDataIntoBuffer() { while(_fin) { int c = _fin.get(); if (c>=0 && c<=255) { _buffer.push_back(c); } } } void XmlNode::Input::skipWhiteSpace() { while(_currentPos<_buffer.size() && (_buffer[_currentPos]==' ' || _buffer[_currentPos]=='\t' || _buffer[_currentPos]=='\n' || _buffer[_currentPos]=='\r')) { //OSG_NOTICE<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<type = XmlNode::COMMENT; children.push_back(commentNode); input += 4; XmlNode::Input::size_type end = input.find("-->"); commentNode->contents = input.substr(0, end); if (end!=std::string::npos) { OSG_INFO<<"Valid Comment record ["<contents<<"]"<contents<<"]"<"); std::string comment = input.substr(0, end); if (end!=std::string::npos) { OSG_INFO<<"Valid end tag ["<type = XmlNode::INFORMATION; children.push_back(commentNode); ++input; XmlNode::Input::size_type end = input.find(">"); commentNode->contents = input.substr(0, end); if (end!=std::string::npos) { OSG_INFO<<"Valid information record ["<contents<<"]"<contents<<"]"<type = XmlNode::INFORMATION; children.push_back(commentNode); input += 9; XmlNode::Input::size_type end = input.find("]]>"); commentNode->contents = input.substr(0, end); if (end!=std::string::npos) { OSG_INFO<<"Valid information record ["<contents<<"]"<contents<<"]"<type = XmlNode::INFORMATION; children.push_back(commentNode); input += 2; XmlNode::Input::size_type end = input.find("?>"); commentNode->contents = input.substr(0, end); if (end!=std::string::npos) { OSG_INFO<<"Valid information record ["<contents<<"]"<contents<<"]"<type = XmlNode::NODE; children.push_back(childNode); input += 1; input.skipWhiteSpace(); int c = 0; while ((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='>' && c!='/') { childNode->name.push_back(c); ++input; } while ((c=input[0])>=0 && c!='>' && c!='/') { Input::size_type prev_pos = input.currentPosition(); input.skipWhiteSpace(); std::string option; std::string value; if (input[0]=='"') { option.push_back(input[0]); ++input; while((c=input[0])>=0 && c!='"') { if (c=='&') readAndReplaceControl(option, input); else { option.push_back(c); ++input; } } option.push_back(input[0]); ++input; } else { while((c=input[0])>=0 && c!='>' && c!='/' && c!='"' && c!='\'' && c!='=' && c!=' ' && c!='\n' && c!='\r') { option.push_back(c); ++input; } } input.skipWhiteSpace(); if (input[0]=='=') { ++input; input.skipWhiteSpace(); if (input[0]=='"') { ++input; while((c=input[0])>=0 && c!='"') { if (c=='&') readAndReplaceControl(value, input); else { value.push_back(c); ++input; } } ++input; } else if (input[0]=='\'') { ++input; while((c=input[0])>=0 && c!='\'') { if (c=='&') readAndReplaceControl(value, input); else { value.push_back(c); ++input; } } ++input; } else { ++input; while((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='"' && c!='\'' && c!='>') { value.push_back(c); ++input; } } } if (prev_pos == input.currentPosition()) { OSG_NOTICE<<"Error, parser iterator not advanced, position: "<properties[option] = value; } } if ((c=input[0])>=0 && (c=='>' || c=='/')) { ++input; OSG_INFO<<"Valid tag ["<name<<"]"<=0 && c=='>') { ++input; OSG_INFO<<"tag is closed correctly"<type = ATOM; } else OSG_NOTICE<<"Error: tag is not closed correctly"<read(input); if (!result) return false; } if (type==NODE && !children.empty()) type = GROUP; } else { OSG_NOTICE<<"Unclosed tag ["<name<<"]"<"<"; writeString(controlMap, fout, contents); fout<<""<"<"<"<"<second; else fout.put(c); } return true; } bool XmlNode::writeChildren(const ControlMap& /*controlMap*/, std::ostream& fout, const std::string& indent) const { for(Children::const_iterator citr = children.begin(); citr != children.end(); ++citr) { if (!(*citr)->write(fout, indent)) return false; } return true; } bool XmlNode::writeProperties(const ControlMap& controlMap, std::ostream& fout) const { for(Properties::const_iterator oitr = properties.begin(); oitr != properties.end(); ++oitr) { fout<<" "<first<<"=\""; if (!writeString(controlMap,fout,oitr->second)) return false; fout<<"\""; } return true; } bool XmlNode::readAndReplaceControl(std::string& contents, XmlNode::Input& input) { int c = 0; std::string value; while(input && (c=input.get())!=';') { value.push_back(c); } value.push_back(c); if (input._controlToCharacterMap.count(value)!=0) { c = input._controlToCharacterMap[value]; OSG_INFO<<"Read control character "< #include #include #include #include #include #include #include using namespace osgDB; static std::string s_lastSchema; InputStream::InputStream( const osgDB::Options* options ) : _fileVersion(0), _useSchemaData(false), _forceReadingImage(false), _dataDecompress(0) { BEGIN_BRACKET.set( "{", +INDENT_VALUE ); END_BRACKET.set( "}", -INDENT_VALUE ); if ( !options ) return; _options = options; if ( options->getPluginStringData("ForceReadingImage")=="true" ) _forceReadingImage = true; if ( !options->getPluginStringData("CustomDomains").empty() ) { StringList domains, keyAndValue; split( options->getPluginStringData("CustomDomains"), domains, ';' ); for ( unsigned int i=0; i1 ) _domainVersionMap[keyAndValue.front()] = atoi(keyAndValue.back().c_str()); } } std::string schema; if ( !options->getPluginStringData("SchemaFile").empty() ) { schema = options->getPluginStringData("SchemaFile"); if ( s_lastSchema!=schema ) { osgDB::ifstream schemaStream( schema.c_str(), std::ios::in ); if ( !schemaStream.fail() ) readSchema( schemaStream ); schemaStream.close(); s_lastSchema = schema; } } if ( schema.empty() ) { resetSchema(); s_lastSchema.clear(); } // assign dummy object to used for reading field properties that will be discarded. _dummyReadObject = new osg::DummyObject; } InputStream::~InputStream() { if (_dataDecompress) delete _dataDecompress; } int InputStream::getFileVersion( const std::string& d ) const { if ( d.empty() ) return _fileVersion; VersionMap::const_iterator itr = _domainVersionMap.find(d); return itr==_domainVersionMap.end() ? 0 : itr->second; } InputStream& InputStream::operator>>( osg::Vec2b& v ) { char x, y; *this >> x >> y; v.set( x, y ); return *this; } InputStream& InputStream::operator>>( osg::Vec3b& v ) { char x, y, z; *this >> x >> y >> z; v.set( x, y, z ); return *this; } InputStream& InputStream::operator>>( osg::Vec4b& v ) { char x, y, z, w; *this >> x >> y >> z >> w; v.set( x, y, z, w ); return *this; } InputStream& InputStream::operator>>( osg::Vec2ub& v ) { unsigned char x, y; *this >> x >> y; v.set( x, y ); return *this; } InputStream& InputStream::operator>>( osg::Vec3ub& v ) { unsigned char x, y, z; *this >> x >> y >> z; v.set( x, y, z ); return *this; } InputStream& InputStream::operator>>( osg::Vec4ub& v ) { unsigned char r, g, b, a; *this >> r >> g >> b >> a; v.set( r, g, b, a ); return *this; } InputStream& InputStream::operator>>( osg::Vec2s& v ) { *this >> v.x() >> v.y(); return *this; } InputStream& InputStream::operator>>( osg::Vec3s& v ) { *this >> v.x() >> v.y() >> v.z(); return *this; } InputStream& InputStream::operator>>( osg::Vec4s& v ) { *this >> v.x() >> v.y() >> v.z() >> v.w(); return *this; } InputStream& InputStream::operator>>( osg::Vec2us& v ) { *this >> v.x() >> v.y(); return *this; } InputStream& InputStream::operator>>( osg::Vec3us& v ) { *this >> v.x() >> v.y() >> v.z(); return *this; } InputStream& InputStream::operator>>( osg::Vec4us& v ) { *this >> v.x() >> v.y() >> v.z() >> v.w(); return *this; } InputStream& InputStream::operator>>( osg::Vec2i& v ) { *this >> v.x() >> v.y(); return *this; } InputStream& InputStream::operator>>( osg::Vec3i& v ) { *this >> v.x() >> v.y() >> v.z(); return *this; } InputStream& InputStream::operator>>( osg::Vec4i& v ) { *this >> v.x() >> v.y() >> v.z() >> v.w(); return *this; } InputStream& InputStream::operator>>( osg::Vec2ui& v ) { *this >> v.x() >> v.y(); return *this; } InputStream& InputStream::operator>>( osg::Vec3ui& v ) { *this >> v.x() >> v.y() >> v.z(); return *this; } InputStream& InputStream::operator>>( osg::Vec4ui& v ) { *this >> v.x() >> v.y() >> v.z() >> v.w(); return *this; } InputStream& InputStream::operator>>( osg::Vec2f& v ) { *this >> v.x() >> v.y(); return *this; } InputStream& InputStream::operator>>( osg::Vec3f& v ) { *this >> v.x() >> v.y() >> v.z(); return *this; } InputStream& InputStream::operator>>( osg::Vec4f& v ) { *this >> v.x() >> v.y() >> v.z() >> v.w(); return *this; } InputStream& InputStream::operator>>( osg::Vec2d& v ) { *this >> v.x() >> v.y(); return *this; } InputStream& InputStream::operator>>( osg::Vec3d& v ) { *this >> v.x() >> v.y() >> v.z(); return *this; } InputStream& InputStream::operator>>( osg::Vec4d& v ) { *this >> v.x() >> v.y() >> v.z() >> v.w(); return *this; } InputStream& InputStream::operator>>( osg::Quat& q ) { *this >> q.x() >> q.y() >> q.z() >> q.w(); return *this; } InputStream& InputStream::operator>>( osg::Plane& p ) { double p0, p1, p2, p3; *this >> p0 >> p1 >> p2 >> p3; p.set( p0, p1, p2, p3 ); return *this; } #if 0 InputStream& InputStream::operator>>( osg::Matrixf& mat ) { ObjectProperty property(""); *this >> property >> BEGIN_BRACKET; if (property._name == "Matrixf") { // stream has same type as what we want to read so read directly for ( int r=0; r<4; ++r ) { *this >> mat(r, 0) >> mat(r, 1) >> mat(r, 2) >> mat(r, 3); } } else if (property._name == "Matrixd") { // stream has different type than what we want to read so read stream into // a temporary and then copy across to the final matrix double value; for ( int r=0; r<4; ++r ) { for ( int c=0; c<4; ++c) { *this >> value; mat(r,c) = static_cast(value); } } } *this >> END_BRACKET; return *this; } InputStream& InputStream::operator>>( osg::Matrixd& mat ) { ObjectProperty property(""); *this >> property >> BEGIN_BRACKET; if (property._name == "Matrixf") { // stream has different type than what we want to read so read stream into // a temporary and then copy across to the final matrix float value; for ( int r=0; r<4; ++r ) { for ( int c=0; c<4; ++c) { *this >> value; mat(r,c) = static_cast(value); } } } else if (property._name == "Matrixd") { // stream has same type as what we want to read so read directly for ( int r=0; r<4; ++r ) { *this >> mat(r, 0) >> mat(r, 1) >> mat(r, 2) >> mat(r, 3); } } *this >> END_BRACKET; return *this; } #else InputStream& InputStream::operator>>( osg::Matrixf& mat ) { *this >> BEGIN_BRACKET; // stream has different type than what we want to read so read stream into // a temporary and then copy across to the final matrix double value; for ( int r=0; r<4; ++r ) { for ( int c=0; c<4; ++c) { *this >> value; mat(r,c) = static_cast(value); } } *this >> END_BRACKET; return *this; } InputStream& InputStream::operator>>( osg::Matrixd& mat ) { *this >> BEGIN_BRACKET; for ( int r=0; r<4; ++r ) { *this >> mat(r, 0) >> mat(r, 1) >> mat(r, 2) >> mat(r, 3); } *this >> END_BRACKET; return *this; } #endif InputStream& InputStream::operator>>( osg::BoundingBoxf& bb) { float p0, p1, p2, p3, p4, p5; *this >> p0 >> p1 >> p2 >> p3>> p4>> p5; bb.set( p0, p1, p2, p3, p4, p5 ); return *this; } InputStream& InputStream::operator>>( osg::BoundingBoxd& bb) { double p0, p1, p2, p3, p4, p5; *this >> p0 >> p1 >> p2 >> p3>> p4>> p5; bb.set( p0, p1, p2, p3, p4, p5 ); return *this; } InputStream& InputStream::operator>>( osg::BoundingSpheref& bs) { float p0, p1, p2, p3; *this >> p0 >> p1 >> p2 >> p3; bs.set( osg::Vec3f(p0, p1, p2), p3 ); return *this; } InputStream& InputStream::operator>>( osg::BoundingSphered& bs) { double p0, p1, p2, p3; *this >> p0 >> p1 >> p2 >> p3; bs.set( osg::Vec3d(p0, p1, p2), p3 ); return *this; } osg::Array* InputStream::readArray() { osg::ref_ptr array = NULL; unsigned int id = 0; *this >> PROPERTY("ArrayID") >> id; ArrayMap::iterator itr = _arrayMap.find( id ); if ( itr!=_arrayMap.end() ) { return itr->second.get(); } DEF_MAPPEE(ArrayType, type); *this >> type; switch ( type.get() ) { case ID_BYTE_ARRAY: { osg::ByteArray* ba = new osg::ByteArray; readArrayImplementation( ba, 1, CHAR_SIZE); array = ba; } break; case ID_UBYTE_ARRAY: { osg::UByteArray* uba = new osg::UByteArray; readArrayImplementation( uba, 1, CHAR_SIZE ); array = uba; } break; case ID_SHORT_ARRAY: { osg::ShortArray* sa = new osg::ShortArray; readArrayImplementation( sa, 1, SHORT_SIZE ); array = sa; } break; case ID_USHORT_ARRAY: { osg::UShortArray* usa = new osg::UShortArray; readArrayImplementation( usa, 1, SHORT_SIZE ); array = usa; } break; case ID_INT_ARRAY: { osg::IntArray* ia = new osg::IntArray; readArrayImplementation( ia, 1, INT_SIZE ); array = ia; } break; case ID_UINT_ARRAY: { osg::UIntArray* uia = new osg::UIntArray; readArrayImplementation( uia, 1, INT_SIZE ); array = uia; } break; case ID_FLOAT_ARRAY: { osg::FloatArray* fa = new osg::FloatArray; readArrayImplementation( fa, 1, FLOAT_SIZE ); array = fa; } break; case ID_DOUBLE_ARRAY: { osg::DoubleArray* da = new osg::DoubleArray; readArrayImplementation( da, 1, DOUBLE_SIZE ); array = da; } break; case ID_VEC2B_ARRAY: { osg::Vec2bArray* va = new osg::Vec2bArray; readArrayImplementation( va, 2, CHAR_SIZE ); array = va; } break; case ID_VEC3B_ARRAY: { osg::Vec3bArray* va = new osg::Vec3bArray; readArrayImplementation( va, 3, CHAR_SIZE ); array = va; } break; case ID_VEC4B_ARRAY: { osg::Vec4bArray* va = new osg::Vec4bArray; readArrayImplementation( va, 4, CHAR_SIZE ); array = va; } break; case ID_VEC2UB_ARRAY: { osg::Vec2ubArray* va = new osg::Vec2ubArray; readArrayImplementation( va, 2, CHAR_SIZE ); array = va; } break; case ID_VEC3UB_ARRAY: { osg::Vec3ubArray* va = new osg::Vec3ubArray; readArrayImplementation( va, 3, CHAR_SIZE ); array = va; } break; case ID_VEC4UB_ARRAY: { osg::Vec4ubArray* va = new osg::Vec4ubArray; readArrayImplementation( va, 4, CHAR_SIZE ); array = va; } break; case ID_VEC2S_ARRAY: { osg::Vec2sArray* va = new osg::Vec2sArray; readArrayImplementation( va, 2, SHORT_SIZE ); array = va; } break; case ID_VEC3S_ARRAY: { osg::Vec3sArray* va = new osg::Vec3sArray; readArrayImplementation( va, 3, SHORT_SIZE ); array = va; } break; case ID_VEC4S_ARRAY: { osg::Vec4sArray* va = new osg::Vec4sArray; readArrayImplementation( va, 4, SHORT_SIZE ); array = va; } break; case ID_VEC2US_ARRAY: { osg::Vec2usArray* va = new osg::Vec2usArray; readArrayImplementation( va, 2, SHORT_SIZE ); array = va; } break; case ID_VEC3US_ARRAY: { osg::Vec3usArray* va = new osg::Vec3usArray; readArrayImplementation( va, 3, SHORT_SIZE ); array = va; } break; case ID_VEC4US_ARRAY: { osg::Vec4usArray* va = new osg::Vec4usArray; readArrayImplementation( va, 4, SHORT_SIZE ); array = va; } break; case ID_VEC2_ARRAY: { osg::Vec2Array* va = new osg::Vec2Array; readArrayImplementation( va, 2, FLOAT_SIZE ); array = va; } break; case ID_VEC3_ARRAY: { osg::Vec3Array* va = new osg::Vec3Array; readArrayImplementation( va, 3, FLOAT_SIZE ); array = va; } break; case ID_VEC4_ARRAY: { osg::Vec4Array* va = new osg::Vec4Array; readArrayImplementation( va, 4, FLOAT_SIZE ); array = va; } break; case ID_VEC2D_ARRAY: { osg::Vec2dArray* va = new osg::Vec2dArray; readArrayImplementation( va, 2, DOUBLE_SIZE ); array = va; } break; case ID_VEC3D_ARRAY: { osg::Vec3dArray* va = new osg::Vec3dArray; readArrayImplementation( va, 3, DOUBLE_SIZE ); array = va; } break; case ID_VEC4D_ARRAY: { osg::Vec4dArray* va = new osg::Vec4dArray; readArrayImplementation( va, 4, DOUBLE_SIZE ); array = va; } break; case ID_VEC2I_ARRAY: { osg::Vec2iArray* va = new osg::Vec2iArray; readArrayImplementation( va, 2, INT_SIZE ); array = va; } break; case ID_VEC3I_ARRAY: { osg::Vec3iArray* va = new osg::Vec3iArray; readArrayImplementation( va, 3, INT_SIZE ); array = va; } break; case ID_VEC4I_ARRAY: { osg::Vec4iArray* va = new osg::Vec4iArray; readArrayImplementation( va, 4, INT_SIZE ); array = va; } break; case ID_VEC2UI_ARRAY: { osg::Vec2uiArray* va = new osg::Vec2uiArray; readArrayImplementation( va, 2, INT_SIZE ); array = va; } break; case ID_VEC3UI_ARRAY: { osg::Vec3uiArray* va = new osg::Vec3uiArray; readArrayImplementation( va, 3, INT_SIZE ); array = va; } break; case ID_VEC4UI_ARRAY: { osg::Vec4uiArray* va = new osg::Vec4uiArray; readArrayImplementation( va, 4, INT_SIZE ); array = va; } break; default: throwException( "InputStream::readArray(): Unsupported array type." ); } if ( getException() ) return NULL; _arrayMap[id] = array; return array.release(); } osg::PrimitiveSet* InputStream::readPrimitiveSet() { osg::ref_ptr primitive = NULL; DEF_MAPPEE(PrimitiveType, type); DEF_MAPPEE(PrimitiveType, mode); unsigned int numInstances = 0u; *this >> type >> mode; if ( _fileVersion>96 ) { *this >> numInstances; } switch ( type.get() ) { case ID_DRAWARRAYS: { int first = 0, count = 0; *this >> first >> count; osg::DrawArrays* da = new osg::DrawArrays( mode.get(), first, count ); primitive = da; primitive->setNumInstances( numInstances ); } break; case ID_DRAWARRAY_LENGTH: { int first = 0, value = 0; unsigned int size = 0; *this >> first >> size >> BEGIN_BRACKET; osg::DrawArrayLengths* dl = new osg::DrawArrayLengths( mode.get(), first ); for ( unsigned int i=0; i> value; dl->push_back( value ); } *this >> END_BRACKET; primitive = dl; primitive->setNumInstances( numInstances ); } break; case ID_DRAWELEMENTS_UBYTE: { osg::DrawElementsUByte* de = new osg::DrawElementsUByte( mode.get() ); unsigned int size = 0; unsigned char value = 0; *this >> size >> BEGIN_BRACKET; for ( unsigned int i=0; i> value; de->push_back( value ); } *this >> END_BRACKET; primitive = de; primitive->setNumInstances( numInstances ); } break; case ID_DRAWELEMENTS_USHORT: { osg::DrawElementsUShort* de = new osg::DrawElementsUShort( mode.get() ); unsigned int size = 0; unsigned short value = 0; *this >> size >> BEGIN_BRACKET; for ( unsigned int i=0; i> value; de->push_back( value ); } *this >> END_BRACKET; primitive = de; primitive->setNumInstances( numInstances ); } break; case ID_DRAWELEMENTS_UINT: { osg::DrawElementsUInt* de = new osg::DrawElementsUInt( mode.get() ); unsigned int size = 0, value = 0; *this >> size >> BEGIN_BRACKET; for ( unsigned int i=0; i> value; de->push_back( value ); } *this >> END_BRACKET; primitive = de; primitive->setNumInstances( numInstances ); } break; default: throwException( "InputStream::readPrimitiveSet(): Unsupported array type." ); } if ( getException() ) return NULL; return primitive.release(); } osg::Image* InputStream::readImage(bool readFromExternal) { std::string className = "osg::Image"; if ( _fileVersion>94 ) // ClassName property is only supported in 3.1.4 and higher *this >> PROPERTY("ClassName") >> className; unsigned int id = 0; *this >> PROPERTY("UniqueID") >> id; if ( getException() ) return NULL; IdentifierMap::iterator itr = _identifierMap.find( id ); if ( itr!=_identifierMap.end() ) { return static_cast( itr->second.get() ); } std::string name; int writeHint, decision = IMAGE_EXTERNAL; *this >> PROPERTY("FileName"); readWrappedString(name); *this >> PROPERTY("WriteHint") >> writeHint >> decision; if ( getException() ) return NULL; osg::ref_ptr image = NULL; switch ( decision ) { case IMAGE_INLINE_DATA: if ( isBinary() ) { // _origin, _s & _t & _r, _internalTextureFormat int origin, s, t, r, internalFormat; *this >> origin >> s >> t >> r >> internalFormat; // _pixelFormat, _dataType, _packing, _allocationMode int pixelFormat, dataType, packing, mode; *this >> pixelFormat >> dataType >> packing >> mode; // _data unsigned int size = 0; *this >> size; if ( size ) { char* data = new char[size]; if ( !data ) throwException( "InputStream::readImage() Out of memory." ); if ( getException() ) return NULL; readCharArray( data, size ); image = new osg::Image; image->setOrigin( (osg::Image::Origin)origin ); image->setImage( s, t, r, internalFormat, pixelFormat, dataType, (unsigned char*)data, osg::Image::USE_NEW_DELETE, packing ); } // _mipmapData unsigned int levelSize = readSize(); osg::Image::MipmapDataType levels(levelSize); for ( unsigned int i=0; i> levels[i]; } if ( image && levelSize>0 ) image->setMipmapLevels( levels ); readFromExternal = false; } else { // ASCII // _origin, _s & _t & _r, _internalTextureFormat int origin, s, t, r, internalFormat; *this >> PROPERTY("Origin") >> origin; *this >> PROPERTY("Size") >> s >> t >> r; *this >> PROPERTY("InternalTextureFormat") >> internalFormat; // _pixelFormat, _dataType, _packing, _allocationMode int pixelFormat, dataType, packing, mode; *this >> PROPERTY("PixelFormat") >> pixelFormat; *this >> PROPERTY("DataType") >> dataType; *this >> PROPERTY("Packing") >> packing; *this >> PROPERTY("AllocationMode") >> mode; *this >> PROPERTY("Data"); unsigned int levelSize = readSize()-1; *this >> BEGIN_BRACKET; // _data std::vector encodedData; encodedData.resize(levelSize+1); readWrappedString(encodedData.at(0)); // Read all mipmap levels and to also add them to char* data // _mipmapData osg::Image::MipmapDataType levels(levelSize); for ( unsigned int i=1; i<=levelSize; ++i ) { //*this >> levels[i]; readWrappedString(encodedData.at(i)); } Base64decoder d; char* data = d.decode(encodedData, levels); // remove last item as we do not need the actual size // of the image including all mipmaps levels.pop_back(); *this >> END_BRACKET; if ( !data ) throwException( "InputStream::readImage() Decoding of stream failed. Out of memory." ); if ( getException() ) return NULL; image = new osg::Image; image->setOrigin( (osg::Image::Origin)origin ); image->setImage( s, t, r, internalFormat, pixelFormat, dataType, (unsigned char*)data, (osg::Image::AllocationMode)mode, packing ); // Level positions (size of mipmap data) // from actual size of mipmap data read before if ( image && levelSize>0 ) image->setMipmapLevels( levels ); readFromExternal = false; } break; case IMAGE_INLINE_FILE: if ( isBinary() ) { unsigned int size = readSize(); if ( size>0 ) { char* data = new char[size]; if ( !data ) { throwException( "InputStream::readImage(): Out of memory." ); if ( getException() ) return NULL; } readCharArray( data, size ); std::string ext = osgDB::getFileExtension( name ); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension( ext ); if ( reader ) { std::stringstream inputStream; inputStream.write( data, size ); osgDB::ReaderWriter::ReadResult rr = reader->readImage( inputStream ); if ( rr.validImage() ) image = rr.takeImage(); else { OSG_WARN << "InputStream::readImage(): " << rr.message() << std::endl; } } else { OSG_WARN << "InputStream::readImage(): Unable to find a plugin for " << ext << std::endl; } delete[] data; } readFromExternal = false; } break; case IMAGE_EXTERNAL: case IMAGE_WRITE_OUT: break; default: break; } bool loadedFromCache = false; if ( readFromExternal && !name.empty() ) { ReaderWriter::ReadResult rr = Registry::instance()->readImage(name, getOptions()); if (rr.validImage()) { image = rr.takeImage(); loadedFromCache = rr.loadedFromCache(); } else { if (rr.error()) OSG_WARN << rr.message() << std::endl; } if ( !image && _forceReadingImage ) image = new osg::Image; } if (loadedFromCache) { // we don't want to overwrite the properties of the image in the cache as this could cause theading problems if the object is currently being used // so we read the properties from the file into a dummy object and discard the changes. osg::ref_ptr temp_obj = readObjectFields("osg::Object", id, _dummyReadObject.get() ); _identifierMap[id] = image; } else { image = static_cast( readObjectFields("osg::Object", id, image.get()) ); if ( image.valid() ) { image->setFileName( name ); image->setWriteHint( (osg::Image::WriteHint)writeHint ); } } return image.release(); } osg::Object* InputStream::readObject( osg::Object* existingObj ) { std::string className; unsigned int id = 0; *this >> className; if (className=="NULL") { return 0; } *this >> BEGIN_BRACKET >> PROPERTY("UniqueID") >> id; if ( getException() ) return NULL; IdentifierMap::iterator itr = _identifierMap.find( id ); if ( itr!=_identifierMap.end() ) { advanceToCurrentEndBracket(); return itr->second.get(); } osg::ref_ptr obj = readObjectFields( className, id, existingObj ); advanceToCurrentEndBracket(); return obj.release(); } osg::Object* InputStream::readObjectFields( const std::string& className, unsigned int id, osg::Object* existingObj ) { ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper( className ); if ( !wrapper ) { OSG_WARN << "InputStream::readObject(): Unsupported wrapper class " << className << std::endl; return NULL; } osg::ref_ptr obj = existingObj ? existingObj : wrapper->createInstance(); _identifierMap[id] = obj; if ( obj.valid() ) { const StringList& associates = wrapper->getAssociates(); for ( StringList::const_iterator itr=associates.begin(); itr!=associates.end(); ++itr ) { ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(*itr); if ( !assocWrapper ) { OSG_WARN << "InputStream::readObject(): Unsupported associated class " << *itr << std::endl; continue; } _fields.push_back( assocWrapper->getName() ); assocWrapper->read( *this, *obj ); if ( getException() ) return NULL; _fields.pop_back(); } } return obj.release(); } void InputStream::readSchema( std::istream& fin ) { // Read from external ascii stream std::string line; while ( std::getline(fin, line) ) { if ( line[0]=='#' ) continue; // Comment StringList keyAndValue; split( line, keyAndValue, '=' ); if ( keyAndValue.size()<2 ) continue; setWrapperSchema( osgDB::trimEnclosingSpaces(keyAndValue[0]), osgDB::trimEnclosingSpaces(keyAndValue[1]) ); } } InputStream::ReadType InputStream::start( InputIterator* inIterator ) { _fields.clear(); _fields.push_back( "Start" ); ReadType type = READ_UNKNOWN; _in = inIterator; if ( !_in ) throwException( "InputStream: Null stream specified." ); if ( getException() ) return type; _in->setInputStream(this); // Check OSG header information unsigned int version = 0; if ( isBinary() ) { unsigned int typeValue; *this >> typeValue >> version; type = static_cast(typeValue); unsigned int attributes; *this >> attributes; if ( attributes&0x4 ) inIterator->setSupportBinaryBrackets( true ); if ( attributes&0x2 ) _useSchemaData = true; // Record custom domains if ( attributes&0x1 ) { unsigned int numDomains; *this >> numDomains; for ( unsigned int i=0; i> domainName; int domainVersion; *this >> domainVersion; _domainVersionMap[domainName] = domainVersion; } } } if ( !isBinary() ) { std::string typeString; *this >> typeString; if ( typeString=="Scene" ) type = READ_SCENE; else if ( typeString=="Image" ) type = READ_IMAGE; else if ( typeString=="Object" ) type = READ_OBJECT; std::string osgName, osgVersion; *this >> PROPERTY("#Version") >> version; *this >> PROPERTY("#Generator") >> osgName >> osgVersion; while ( matchString("#CustomDomain") ) { std::string domainName; *this >> domainName; int domainVersion; *this >> domainVersion; _domainVersionMap[domainName] = domainVersion; } } // Record file version for back-compatibility checking of wrappers _fileVersion = version; _fields.pop_back(); return type; } void InputStream::decompress() { if ( !isBinary() ) return; _fields.clear(); std::string compressorName; *this >> compressorName; if ( compressorName!="0" ) { std::string data; _fields.push_back( "Decompression" ); BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(compressorName); if ( !compressor ) { OSG_WARN << "InputStream::decompress(): No such compressor " << compressorName << std::endl; } if ( !compressor->decompress(*(_in->getStream()), data) ) throwException( "InputStream: Failed to decompress stream." ); if ( getException() ) return; _dataDecompress = new std::stringstream(data); _in->setStream( _dataDecompress ); _fields.pop_back(); } if ( _useSchemaData ) { _fields.push_back( "SchemaData" ); std::string schemaSource; *this >> schemaSource; std::istringstream iss( schemaSource ); readSchema( iss ); _fields.pop_back(); } } // PROTECTED METHODS void InputStream::setWrapperSchema( const std::string& name, const std::string& properties ) { ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(name); if ( !wrapper ) { OSG_WARN << "InputStream::setSchema(): Unsupported wrapper class " << name << std::endl; return; } StringList schema, methods, keyAndValue; ObjectWrapper::TypeList types; split( properties, schema ); for ( StringList::iterator itr=schema.begin(); itr!=schema.end(); ++itr ) { split( *itr, keyAndValue, ':' ); if ( keyAndValue.size()>1 ) { methods.push_back( keyAndValue.front() ); types.push_back( static_cast(atoi(keyAndValue.back().c_str())) ); } else { methods.push_back( *itr ); types.push_back( BaseSerializer::RW_UNDEFINED ); } keyAndValue.clear(); } wrapper->readSchema( methods, types ); } void InputStream::resetSchema() { const ObjectWrapperManager::WrapperMap& wrappers = Registry::instance()->getObjectWrapperManager()->getWrapperMap(); for ( ObjectWrapperManager::WrapperMap::const_iterator itr=wrappers.begin(); itr!=wrappers.end(); ++itr ) { ObjectWrapper* wrapper = itr->second.get(); wrapper->resetSchema(); } } template void InputStream::readArrayImplementation( T* a, unsigned int numComponentsPerElements, unsigned int componentSizeInBytes ) { int size = 0; *this >> size >> BEGIN_BRACKET; if ( size ) { a->resize( size ); if ( isBinary() ) { readComponentArray( (char*)&((*a)[0]), size, numComponentsPerElements, componentSizeInBytes ); checkStream(); } else { for ( int i=0; i> (*a)[i]; } } *this >> END_BRACKET; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/0000755000175000017500000000000013151044751021623 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/Version.cpp0000644000175000017500000000152513151044751023757 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include extern "C" { const char* osgViewerGetVersion() { return osgGetVersion(); } const char* osgViewerGetLibraryName() { return "OpenSceneGraph Viewer Library"; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/PixelBufferX11.cpp0000644000175000017500000003627313151044751025047 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ /* Note, elements of PixelBufferX11 have used Prodcer/RenderSurface_X11.cpp as both * a guide to use of X11/GLX and copiying directly in the case of setBorder(). * These elements are license under OSGPL as above, with Copyright (C) 2001-2004 Don Burns. */ #include #include #include #include #include using namespace osgViewer; PixelBufferX11::PixelBufferX11(osg::GraphicsContext::Traits* traits) : _valid(false), _pbuffer(0), _visualInfo(0), _initialized(false), _realized(false), _useGLX1_3(false), _useSGIX(false) #ifdef GLX_SGIX_pbuffer ,_glXCreateGLXPbufferSGIX(NULL), _glXDestroyGLXPbufferSGIX(NULL), _glXQueryGLXPbufferSGIX(NULL), _glXGetFBConfigFromVisualSGIX(NULL) #endif { _traits = traits; init(); if (valid()) { setState( new osg::State ); getState()->setGraphicsContext(this); if (_traits.valid() && _traits->sharedContext.valid()) { getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); incrementContextIDUsageCount( getState()->getContextID() ); } else { getState()->setContextID( osg::GraphicsContext::createNewContextID() ); } } } PixelBufferX11::~PixelBufferX11() { close(true); } #if defined(GLX_VERSION_1_3) || defined(GLX_SGIX_pbuffer) bool PixelBufferX11::createVisualInfo() { typedef std::vector Attributes; Attributes attributes; attributes.push_back(GLX_USE_GL); attributes.push_back(GLX_RGBA); if (_traits->doubleBuffer) attributes.push_back(GLX_DOUBLEBUFFER); attributes.push_back(GLX_RED_SIZE); attributes.push_back(_traits->red); attributes.push_back(GLX_GREEN_SIZE); attributes.push_back(_traits->green); attributes.push_back(GLX_BLUE_SIZE); attributes.push_back(_traits->blue); attributes.push_back(GLX_DEPTH_SIZE); attributes.push_back(_traits->depth); if (_traits->alpha) { attributes.push_back(GLX_ALPHA_SIZE); attributes.push_back(_traits->alpha); } if (_traits->stencil) { attributes.push_back(GLX_STENCIL_SIZE); attributes.push_back(_traits->stencil); } #if defined(GLX_SAMPLE_BUFFERS) && defined (GLX_SAMPLES) if (_traits->sampleBuffers) { attributes.push_back(GLX_SAMPLE_BUFFERS); attributes.push_back(_traits->sampleBuffers); } if (_traits->sampleBuffers) { attributes.push_back(GLX_SAMPLES); attributes.push_back(_traits->samples); } #endif // TODO // GLX_AUX_BUFFERS // GLX_ACCUM_RED_SIZE // GLX_ACCUM_GREEN_SIZE attributes.push_back(None); _visualInfo = glXChooseVisual( _display, _traits->screenNum, &(attributes.front()) ); return _visualInfo != 0; } void PixelBufferX11::init() { if (_initialized) return; if (!_traits) { _valid = false; return; } if (_traits->target != 0) { // we don't support Pbuffer render to texture under GLX. _valid = false; return; } _display = XOpenDisplay(_traits->displayName().c_str()); unsigned int screen = _traits->screenNum; if (!_display) { OSG_NOTICE<<"Error: Unable to open display \"" << XDisplayName(_traits->displayName().c_str()) << "\"."<displayName().c_str()) <<" has no GLX extension." << std::endl; XCloseDisplay( _display ); _display = 0; _valid = false; return; } // OSG_NOTICE<<"GLX extension, errorBase="<displayName().c_str()) << " can not query GLX version." << std::endl; XCloseDisplay( _display ); _display = 0; _valid = false; return; } // Just be paranoid, if we are older than 1.1, we cannot even call glxQueryExtensionString if (major < 1 || (1 == major && minor < 1)) { OSG_NOTICE << "Error: " << XDisplayName(_traits->displayName().c_str()) << " GLX version " << major << "." << minor << " is too old." << std::endl; XCloseDisplay( _display ); _display = 0; _valid = false; return; } bool haveGLX1_3 = false; bool haveSGIX_pbuffer = false; // We need to have at least GLX 1.3 to use getFBConfigFromVisual and glXCreatePbuffer if (1 < major || (1 == major && 3 <= minor)) { haveGLX1_3 = true; } #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_pbuffer) // We need at least GLX 1.1 for glXQueryExtensionsString if (!haveGLX1_3 && 1 <= minor) { const char *extensions = glXQueryExtensionsString(_display, screen); haveSGIX_pbuffer = osg::isExtensionInExtensionString("GLX_SGIX_pbuffer", extensions) && osg::isExtensionInExtensionString("GLX_SGIX_fbconfig", extensions); if (haveSGIX_pbuffer) { osg::setGLExtensionFuncPtr(_glXCreateGLXPbufferSGIX, "glXDestroyGLXPbufferSGIX"); osg::setGLExtensionFuncPtr(_glXDestroyGLXPbufferSGIX, "glXDestroyGLXPbufferSGIX"); osg::setGLExtensionFuncPtr(_glXQueryGLXPbufferSGIX, "glXDestroyGLXPbufferSGIX"); osg::setGLExtensionFuncPtr(_glXGetFBConfigFromVisualSGIX, "glXGetFBConfigFromVisualSGIX"); if (_glXCreateGLXPbufferSGIX == NULL || _glXDestroyGLXPbufferSGIX == NULL || _glXQueryGLXPbufferSGIX == NULL || _glXGetFBConfigFromVisualSGIX == NULL) { haveSGIX_pbuffer = false; } } } #endif if (!haveGLX1_3 && !haveSGIX_pbuffer) { OSG_NOTICE << "Error: " << XDisplayName(_traits->displayName().c_str()) << " no Pbuffer support in GLX available." << std::endl; XCloseDisplay( _display ); _display = 0; _valid = false; return; } if (!createVisualInfo()) { _traits->red /= 2; _traits->green /= 2; _traits->blue /= 2; _traits->alpha /= 2; _traits->depth /= 2; OSG_INFO<<"Relaxing traits"<(_traits->sharedContext.get()); Context sharedContext = graphicsHandleX11 ? graphicsHandleX11->getContext() : 0; _context = glXCreateContext( _display, _visualInfo, sharedContext, True ); if (!_context) { OSG_NOTICE<<"Error: Unable to create OpenGL graphics context."<visualid ) { typedef std::vector AttributeList; AttributeList attributes; attributes.push_back( GLX_PBUFFER_WIDTH ); attributes.push_back( _traits->width ); attributes.push_back( GLX_PBUFFER_HEIGHT ); attributes.push_back( _traits->height ); attributes.push_back( GLX_LARGEST_PBUFFER ); attributes.push_back( GL_TRUE ); attributes.push_back( 0L ); _pbuffer = glXCreatePbuffer(_display, fbconfigs[i], &attributes.front() ); _useGLX1_3 = true; } } } if (_pbuffer) { int iWidth = 0; int iHeight = 0; glXQueryDrawable(_display, _pbuffer, GLX_WIDTH , (unsigned int *)&iWidth); glXQueryDrawable(_display, _pbuffer, GLX_HEIGHT , (unsigned int *)&iHeight); if (_traits->width != iWidth || _traits->height != iHeight) { OSG_NOTICE << "PixelBufferX11::init(), pbuffer created with different size then requsted" << std::endl; OSG_NOTICE << "\tRequested size (" << _traits->width << "," << _traits->height << ")" << std::endl; OSG_NOTICE << "\tPbuffer size (" << iWidth << "," << iHeight << ")" << std::endl; _traits->width = iWidth; _traits->height = iHeight; } } XFree( fbconfigs ); } #endif #ifdef GLX_SGIX_pbuffer // If we still have no pbuffer but a capable display with the SGIX extension, try to use that if (!_pbuffer && haveSGIX_pbuffer) { GLXFBConfigSGIX fbconfig = _glXGetFBConfigFromVisualSGIX( _display, _visualInfo ); typedef std::vector AttributeList; AttributeList attributes; attributes.push_back( GLX_LARGEST_PBUFFER_SGIX ); attributes.push_back( GL_TRUE ); attributes.push_back( 0L ); _pbuffer = _glXCreateGLXPbufferSGIX(_display, fbconfig, _traits->width, _traits->height, &attributes.front() ); if (_pbuffer) { _useSGIX = true; int iWidth = 0; int iHeight = 0; _glXQueryGLXPbufferSGIX(_display, _pbuffer, GLX_WIDTH_SGIX , (unsigned int *)&iWidth); _glXQueryGLXPbufferSGIX(_display, _pbuffer, GLX_HEIGHT_SGIX, (unsigned int *)&iHeight); if (_traits->width != iWidth || _traits->height != iHeight) { OSG_NOTICE << "PixelBufferX11::init(), SGIX_pbuffer created with different size then requsted" << std::endl; OSG_NOTICE << "\tRequested size (" << _traits->width << "," << _traits->height << ")" << std::endl; OSG_NOTICE << "\tPbuffer size (" << iWidth << "," << iHeight << ")" << std::endl; _traits->width = iWidth; _traits->height = iHeight; } } XFree( fbconfig ); } #endif if (!_pbuffer) { OSG_NOTICE<<"Error: Unable to create pbuffer."< #include #include #include #include #include #include #include #include #include /* For CARD16 */ #ifdef OSGVIEWER_USE_XRANDR #include #endif #include using namespace osgViewer; #ifdef OSG_USE_EGL bool checkEGLError(const char* str) { EGLint err = eglGetError(); if (err != EGL_SUCCESS) { OSG_WARN<<"Warning: "<second; itr = _standardKeymap.find(key); if (itr != _standardKeymap.end()) return itr->second; return key; } bool remapExtendedKey(int& key) { KeyMap::iterator itr = _extendedKeymap.find(key); if (itr != _extendedKeymap.end()) { key = itr->second; return true; } else return false; } protected: typedef std::map KeyMap; KeyMap _extendedKeymap; KeyMap _standardKeymap; }; static bool remapExtendedX11Key(int& key) { static X11KeyboardMap s_x11KeyboardMap; return s_x11KeyboardMap.remapExtendedKey(key); } // Functions to handle key maps of type char[32] as contained in // an XKeymapEvent or returned by XQueryKeymap(). static inline bool keyMapGetKey(const char* map, unsigned int key) { return (map[(key & 0xff) / 8] & (1 << (key & 7))) != 0; } static inline void keyMapSetKey(char* map, unsigned int key) { map[(key & 0xff) / 8] |= (1 << (key & 7)); } static inline void keyMapClearKey(char* map, unsigned int key) { map[(key & 0xff) / 8] &= ~(1 << (key & 7)); } GraphicsWindowX11::~GraphicsWindowX11() { close(true); } Display* GraphicsWindowX11::getDisplayToUse() const { if (_threadOfLastMakeCurrent==0) { return _display; } if (OpenThreads::Thread::CurrentThread()==_threadOfLastMakeCurrent) { return _display; } else { return _eventDisplay; } } bool GraphicsWindowX11::createVisualInfo() { if (_visualInfo) { #ifdef OSG_USE_EGL delete _visualInfo; #else XFree(_visualInfo); #endif _visualInfo = 0; } if( _window != 0 ) { XWindowAttributes watt; XGetWindowAttributes( _display, _window, &watt ); XVisualInfo temp; temp.visualid = XVisualIDFromVisual(watt.visual); int n; _visualInfo = XGetVisualInfo( _display, VisualIDMask, &temp, &n ); } else { #ifdef OSG_USE_EGL _visualInfo = new XVisualInfo; int depth = DefaultDepth( _display, _traits->screenNum ); if (XMatchVisualInfo( _display, _traits->screenNum, depth, TrueColor, _visualInfo )==0) { OSG_NOTICE<<"GraphicsWindowX11::createVisualInfo() failed."< Attributes; Attributes attributes; attributes.push_back(GLX_USE_GL); attributes.push_back(GLX_RGBA); if (_traits->doubleBuffer) attributes.push_back(GLX_DOUBLEBUFFER); if (_traits->quadBufferStereo) attributes.push_back(GLX_STEREO); attributes.push_back(GLX_RED_SIZE); attributes.push_back(_traits->red); attributes.push_back(GLX_GREEN_SIZE); attributes.push_back(_traits->green); attributes.push_back(GLX_BLUE_SIZE); attributes.push_back(_traits->blue); attributes.push_back(GLX_DEPTH_SIZE); attributes.push_back(_traits->depth); if (_traits->alpha) { attributes.push_back(GLX_ALPHA_SIZE); attributes.push_back(_traits->alpha); } if (_traits->stencil) { attributes.push_back(GLX_STENCIL_SIZE); attributes.push_back(_traits->stencil); } #if defined(GLX_SAMPLE_BUFFERS) && defined (GLX_SAMPLES) if (_traits->sampleBuffers) { attributes.push_back(GLX_SAMPLE_BUFFERS); attributes.push_back(_traits->sampleBuffers); } if (_traits->samples) { attributes.push_back(GLX_SAMPLES); attributes.push_back(_traits->samples); } #endif // TODO // GLX_AUX_BUFFERS // GLX_ACCUM_RED_SIZE // GLX_ACCUM_GREEN_SIZE attributes.push_back(None); _visualInfo = glXChooseVisual( _display, _traits->screenNum, &(attributes.front()) ); #endif } return _visualInfo != 0; } bool GraphicsWindowX11::checkAndSendEventFullScreenIfNeeded(Display* display, int x, int y, int width, int height, bool windowDecoration) { osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (wsi == NULL) { OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; return false; } unsigned int screenWidth; unsigned int screenHeight; wsi->getScreenResolution(*_traits, screenWidth, screenHeight); bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !windowDecoration; if (isFullScreen) { resized(x, y, width, height); getEventQueue()->windowResize(x, y, width, height, getEventQueue()->getTime()); } Atom netWMStateAtom = XInternAtom(display, "_NET_WM_STATE", True); Atom netWMStateFullscreenAtom = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", True); if (netWMStateAtom != None && netWMStateFullscreenAtom != None) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = _window; xev.xclient.message_type = netWMStateAtom; xev.xclient.format = 32; xev.xclient.data.l[0] = isFullScreen ? 1 : 0; xev.xclient.data.l[1] = netWMStateFullscreenAtom; xev.xclient.data.l[2] = 0; XSendEvent(display, RootWindow(display, DefaultScreen(display)), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); return true; } return false; } #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) #define MWM_DECOR_ALL (1L<<0) #define MWM_DECOR_BORDER (1L<<1) #define MWM_DECOR_RESIZEH (1L<<2) #define MWM_DECOR_TITLE (1L<<3) #define MWM_DECOR_MENU (1L<<4) #define MWM_DECOR_MINIMIZE (1L<<5) #define MWM_DECOR_MAXIMIZE (1L<<6) #define MWM_FUNC_ALL (1L<<0) #define MWM_FUNC_RESIZE (1L<<1) #define MWM_FUNC_MOVE (1L<<2) #define MWM_FUNC_MINIMIZE (1L<<3) #define MWM_FUNC_MAXIMIZE (1L<<4) #define MWM_FUNC_CLOSE (1L<<5) bool GraphicsWindowX11::setWindowDecorationImplementation(bool flag) { Display* display = getDisplayToUse(); XMapWindow(display, _window ); checkAndSendEventFullScreenIfNeeded(display, _traits->x, _traits->y, _traits->width, _traits->height, flag); struct { unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status; } wmHints; Atom atom; bool result = false; if( (atom = XInternAtom( display, "_MOTIF_WM_HINTS", 0 )) != None ) { if (flag) { wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; wmHints.functions = MWM_FUNC_ALL; wmHints.decorations = MWM_DECOR_ALL; wmHints.inputMode = 0; wmHints.status = 0; // if traits says not resize we want to set the functions to exlude MWM_FUNC_RESIZE, // but this bitmask needs to be set if the MWM_FUNC_ALL bit is already set in order to toggle it off. if (_traits.valid() && !_traits->supportsResize) wmHints.functions = wmHints.functions | MWM_FUNC_RESIZE; } else { wmHints.flags = MWM_HINTS_DECORATIONS; wmHints.functions = 0; wmHints.decorations = 0; wmHints.inputMode = 0; wmHints.status = 0; } XChangeProperty( display, _window, atom, atom, 32, PropModeReplace, (unsigned char *)&wmHints, 5 ); result = true; } else { OSG_NOTICE<<"Error: GraphicsWindowX11::setWindowDecorationImplementation(" << flag << ") - couldn't change decorations." << std::endl; result = false; } XFlush(display); XSync(display,0); // add usleep here to give window manager a chance to handle the request, if // we don't add this sleep then any X11 calls right afterwards can produce // X11 errors. usleep(100000); return result; } bool GraphicsWindowX11::setWindowRectangleImplementation(int x, int y, int width, int height) { if (!_initialized) return false; Display* display = getDisplayToUse(); checkAndSendEventFullScreenIfNeeded(display, x, y, width, height, _traits->windowDecoration); XMoveResizeWindow(display, _window, x, y, width, height); XFlush(display); XSync(display, 0); // add usleep here to give window manager a chance to handle the request, if // we don't add this sleep then any X11 calls right afterwards can produce // X11 errors. usleep(100000); return true; } void GraphicsWindowX11::setWindowName(const std::string& name) { if( _window == 0) return; // char *slist[] = { name.c_str(), 0L }; // XTextProperty xtp; // XStringListToTextProperty( slist, 1, &xtp ); Display* display = getDisplayToUse(); if( !display ) return; // XSetWMName( display, _window, &xtp ); XStoreName( display, _window, name.c_str() ); XSetIconName( display, _window, name.c_str() ); XFlush(display); XSync(display,0); _traits->windowName = name; } void GraphicsWindowX11::setCursor(MouseCursor mouseCursor) { Cursor newCursor = getOrCreateCursor(mouseCursor); if (newCursor == _currentCursor) return; _currentCursor = newCursor; if (!_window) return; Display* display = getDisplayToUse(); if (!display) return; XDefineCursor( display, _window, _currentCursor ); XFlush(display); XSync(display, 0); _traits->useCursor = (_currentCursor != getOrCreateCursor(NoCursor)); } Cursor GraphicsWindowX11::getOrCreateCursor(MouseCursor mouseCursor) { std::map::iterator i = _mouseCursorMap.find(mouseCursor); if (i != _mouseCursorMap.end()) return i->second; Display* display = getDisplayToUse(); if (!display) return None; switch (mouseCursor) { case NoCursor: { // create an empty mouse cursor, note that it is safe to destroy the Pixmap just past cursor creation // since the resource in the x server is reference counted. char buff[2] = {0,0}; XColor ncol = {0,0,0,0,DoRed|DoGreen|DoBlue,0}; Pixmap pixmap = XCreateBitmapFromData( display, _parent, buff, 1, 1); _mouseCursorMap[mouseCursor] = XCreatePixmapCursor( display, pixmap, pixmap, &ncol, &ncol, 0, 0 ); XFreePixmap(display, pixmap); // Important to have the pixmap and the buffer still available when the request is sent to the server ... XFlush(display); XSync(display, 0); break; } case RightArrowCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_left_ptr ); break; case LeftArrowCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_left_arrow ); break; case InfoCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_hand1 ); break; case DestroyCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_pirate ); break; case HelpCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_question_arrow ); break; case CycleCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_exchange ); break; case SprayCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_spraycan ); break; case WaitCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_watch ); break; case TextCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_xterm ); break; case CrosshairCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_crosshair ); break; case UpDownCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_sb_v_double_arrow ); break; case LeftRightCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_sb_h_double_arrow ); break; case TopSideCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_side ); break; case BottomSideCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_side ); break; case LeftSideCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_left_side ); break; case RightSideCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_right_side ); break; case TopLeftCorner: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_left_corner ); break; case TopRightCorner: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_top_right_corner ); break; case BottomRightCorner: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_right_corner ); break; case BottomLeftCorner: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_bottom_left_corner ); break; case HandCursor: _mouseCursorMap[mouseCursor] = XCreateFontCursor( display, XC_hand1 ); break; case InheritCursor: default: _mouseCursorMap[mouseCursor] = None; break; }; return _mouseCursorMap[mouseCursor]; } void GraphicsWindowX11::init() { if (_initialized) return; if (!_traits) { _valid = false; return; } // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); WindowData* inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); Window windowHandle = inheritedWindowData ? inheritedWindowData->_window : 0; _ownsWindow = windowHandle == 0; _display = XOpenDisplay(_traits->displayName().c_str()); if (!_display) { OSG_NOTICE<<"Error: Unable to open display \"" << XDisplayName(_traits->displayName().c_str()) << "\"."<displayName().c_str()) <<" has no GLX extension." << std::endl; XCloseDisplay( _display ); _display = 0; _valid = false; return; } #endif // OSG_NOTICE<<"GLX extension, errorBase="<(_traits->sharedContext.get()); Context sharedContext = graphicsHandleX11 ? graphicsHandleX11->getContext() : 0; #ifdef OSG_USE_EGL _valid = _ownsWindow ? createWindow() : setWindow(windowHandle); if (!_valid) { XCloseDisplay( _display ); _display = 0; return; } OSG_NOTICE<<"GraphicsWindowX11::init() - window created ="<<_valid< Attributes; Attributes attributes; attributes.push_back(EGL_RED_SIZE); attributes.push_back(_traits->red); attributes.push_back(EGL_GREEN_SIZE); attributes.push_back(_traits->green); attributes.push_back(EGL_BLUE_SIZE); attributes.push_back(_traits->blue); attributes.push_back(EGL_DEPTH_SIZE); attributes.push_back(_traits->depth); if (_traits->alpha) { attributes.push_back(EGL_ALPHA_SIZE); attributes.push_back(_traits->alpha); } if (_traits->stencil) { attributes.push_back(EGL_STENCIL_SIZE); attributes.push_back(_traits->stencil); } if (_traits->sampleBuffers) { attributes.push_back(EGL_SAMPLE_BUFFERS); attributes.push_back(_traits->sampleBuffers); } if (_traits->samples) { attributes.push_back(EGL_SAMPLES); attributes.push_back(_traits->samples); } attributes.push_back(EGL_RENDERABLE_TYPE); attributes.push_back(OSG_EGL_OPENGL_TARGET_BIT); attributes.push_back(EGL_NONE); attributes.push_back(EGL_NONE); int numConfigs; if (!eglChooseConfig(_eglDisplay, &(attributes.front()), &eglConfig, 1, &numConfigs) || (numConfigs != 1)) { OSG_NOTICE<<"GraphicsWindowX11::init() - eglChooseConfig() failed."<syncWindowRectangleWithGraphicsContext(); } bool GraphicsWindowX11::createWindow() { unsigned int screen = _traits->screenNum; _eventDisplay = XOpenDisplay(_traits->displayName().c_str()); _parent = RootWindow( _display, screen ); XWindowAttributes watt; XGetWindowAttributes( _display, _parent, &watt ); // unsigned int parentWindowHeight = watt.height; XSetWindowAttributes swatt; swatt.colormap = XCreateColormap( _display, _parent, _visualInfo->visual, AllocNone); //swatt.colormap = DefaultColormap( _dpy, 10 ); swatt.background_pixel = 0; swatt.border_pixel = 0; swatt.event_mask = 0; unsigned long mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap; if (_traits->overrideRedirect) { swatt.override_redirect = true; mask |= CWOverrideRedirect; OSG_INFO<<"Setting override redirect"<x; int y = _traits->y; int width = _traits->width; int height = _traits->height; unsigned int screenWidth; unsigned int screenHeight; wsi->getScreenResolution(*_traits, screenWidth, screenHeight); bool doFullSceenWorkAround = false; bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !_traits->windowDecoration; if (isFullScreen && !_traits->overrideRedirect) { // follows is hack to get around problems with toggling off full screen with modern X11 window // managers that try to be too clever when toggling off full screen and ignore the window size // calls made by the OSG when the initial window size is full screen. Atom netWMStateAtom = XInternAtom(_display, "_NET_WM_STATE", True); Atom netWMStateFullscreenAtom = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", True); // we have a modern X11 server so assume we need the do the full screen hack. if (netWMStateAtom != None && netWMStateFullscreenAtom != None) { // artificially reduce the initial window size so that the windowing // system has a size to go back to when toggling off full screen, // we don't have to worry about the window being initially smaller as the // setWindowDecoration(..) implementation with enable full screen for us x = width/4; y = height/4; width /= 2; height /= 2; doFullSceenWorkAround = true; } } _window = XCreateWindow( _display, _parent, x, y, width, height, 0, _visualInfo->depth, InputOutput, _visualInfo->visual, mask, &swatt ); if (!_window) { OSG_NOTICE<<"Error: Unable to create Window."<x; sh.y = _traits->y; sh.width = _traits->width; sh.height = _traits->height; XSetStandardProperties( _display, _window, _traits->windowName.c_str(), _traits->windowName.c_str(), None, 0, 0, &sh); setWindowDecoration(_traits->windowDecoration); useCursor(_traits->useCursor); _deleteWindow = XInternAtom (_display, "WM_DELETE_WINDOW", False); XSetWMProtocols(_display, _window, &_deleteWindow, 1); XFlush( _display ); XSync( _display, 0 ); // get window geometry relative to root window/screen Window child_return; int windowX, windowY; XGetWindowAttributes( _display, _window, &watt ); XTranslateCoordinates( _display, _window, watt.root, watt.x, watt.y, &windowX, &windowY, &child_return); if (_traits->x != windowX || _traits->y != windowY ||_traits->width != watt.width || _traits->height != watt.height) { if (doFullSceenWorkAround) { OSG_INFO<<"Full Screen failed, resizing manually"<x, _traits->y, _traits->width, _traits->height); XFlush(_display); XSync(_display, 0); XGetWindowAttributes( _display, _window, &watt ); XTranslateCoordinates( _display, _window, watt.root, watt.x, watt.y, &windowX, &windowY, &child_return); } resized( windowX, windowY, watt.width, watt.height ); } //OSG_NOTICE<<"After sync apply.x = "<x = watt.x; _traits->y = watt.y; _traits->width = watt.width; _traits->height = watt.height; _parent = DefaultRootWindow( _display ); //_traits->supportsResize = false; _traits->windowDecoration = false; if (_traits->windowName.size()) setWindowName(_traits->windowName); _eventDisplay = XOpenDisplay(_traits->displayName().c_str()); XFlush( _eventDisplay ); XSync( _eventDisplay, 0 ); return true; } bool GraphicsWindowX11::realizeImplementation() { if (_realized) { OSG_NOTICE<<"GraphicsWindowX11::realizeImplementation() Already realized"<syncWindowRectangleWithGraphicsContext(); // Window temp = _window; // XSetWMColormapWindows( _display, _window, &temp, 1); _realized = true; return true; } bool GraphicsWindowX11::makeCurrentImplementation() { if (!_realized) { OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<vsync) { unsigned int counter; glXGetVideoSyncSGI(&counter); glXWaitVideoSyncSGI(1, 0, &counter); } #endif glXSwapBuffers( _display, _window ); #endif while( XPending(_display) ) { XEvent ev; XNextEvent( _display, &ev ); switch( ev.type ) { case ClientMessage: { if (static_cast(ev.xclient.data.l[0]) == _deleteWindow) { OSG_INFO<<"DeleteWindow event received"<closeWindow(); } } } } } bool GraphicsWindowX11::checkEvents() { if (!_realized) return false; Display* display = _eventDisplay; double baseTime = _timeOfLastCheckEvents; double eventTime = baseTime; double resizeTime = eventTime; _timeOfLastCheckEvents = getEventQueue()->getTime(); if (baseTime>_timeOfLastCheckEvents) baseTime = _timeOfLastCheckEvents; // OSG_NOTICE<<"GraphicsWindowX11::checkEvents() : getEventQueue()->getCurrentEventState()->getGraphicsContext()="<getCurrentEventState()->getGraphicsContext()<x; int windowY = _traits->y; int windowWidth = _traits->width; int windowHeight = _traits->height; bool needNewWindowSize = false; Time firstEventTime = 0; // OSG_NOTICE<<"Check events"<(ev.xclient.data.l[0]) == _deleteWindow) { OSG_INFO<<"DeleteWindow event received"<closeWindow(eventTime); } break; } case Expose : OSG_INFO<<"Expose x="<(relativeTime)*0.001; int wx, wy; Window win = 0L; if( ev.xmotion.same_screen ) { wx = ev.xmotion.x; wy = ev.xmotion.y; } else { // the mouse in on another screen so need to compute the // coordinates of the mouse position relative to an absolute position // then take away the position of the original window/screen to get // the coordinates relative to the original position. Window root; int rx, ry; unsigned int buttons; int screenOrigin_x = 0; int screenOrigin_y = 0; int i; for(i= 0; i < ScreenCount(display); i++ ) { if( XQueryPointer( display, RootWindow(display, i), &root, &win, &rx, &ry, &wx, &wy, &buttons) ) { break; } screenOrigin_x += DisplayWidth(display, i); } for(i= 0; i < static_cast(_traits->screenNum); i++ ) { screenOrigin_x -= DisplayWidth(display, i); } int dest_x_return, dest_y_return; Window child_return; XTranslateCoordinates(display, _window, _parent, 0, 0, &dest_x_return, &dest_y_return, &child_return); wx += (screenOrigin_x - dest_x_return); wy += (screenOrigin_y - dest_y_return); } float mx = wx; float my = wy; transformMouseXY(mx, my); getEventQueue()->mouseMotion(mx, my, eventTime); // OSG_NOTICE<<"MotionNotify wx="<x || windowY != _traits->y || windowWidth != _traits->width || windowHeight != _traits->height) { resized(windowX, windowY, windowWidth, windowHeight); getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime); // request window repaint if window size was changed if (windowWidth != _traits->width || windowHeight != _traits->height) { requestRedraw(); } } return !(getEventQueue()->empty()); } void GraphicsWindowX11::grabFocus() { Display* display = getDisplayToUse(); XSetInputFocus( display, _window, RevertToNone, CurrentTime ); XFlush(display); XSync(display,0); } void GraphicsWindowX11::grabFocusIfPointerInWindow() { Window win, root; int wx, wy, rx, ry; unsigned int buttons; Display* display = getDisplayToUse(); if( XQueryPointer( display, _window, &root, &win, &rx, &ry, &wx, &wy, &buttons)) { #if 0 if (wx>=0 && wx<_traits->width && wy>=0 && wy<_traits->height) { grabFocus(); } #else grabFocus(); #endif } } void GraphicsWindowX11::transformMouseXY(float& x, float& y) { if (getEventQueue()->getUseFixedMouseInputRange()) { osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState(); x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width); y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height); } } void GraphicsWindowX11::adaptKey(XKeyEvent& keyevent, int& keySymbol, int& unmodifiedKeySymbol) { unsigned char buffer_return[32]; int bytes_buffer = 32; KeySym keysym_return; int numChars = XLookupString(&keyevent, reinterpret_cast(buffer_return), bytes_buffer, &keysym_return, NULL); keySymbol = keysym_return; if (!remapExtendedX11Key(keySymbol) && (numChars==1)) { keySymbol = buffer_return[0]; } unmodifiedKeySymbol = XkbKeycodeToKeysym(keyevent.display, keyevent.keycode, 0, 0); } // Function to inject artificial key presses/releases. void GraphicsWindowX11::forceKey(int key, double time, bool state) { if (!(state ^ keyMapGetKey(_keyMap, key))) return; // already pressed/released XKeyEvent event; event.serial = 0; event.send_event = True; event.display = _eventDisplay; event.window = _window; event.subwindow = 0; event.time = 0; event.x = 0; event.y = 0; event.x_root = 0; event.y_root = 0; event.state = getModifierMask() | (_modifierState & (LockMask | _numLockMask)); event.keycode = key; event.same_screen = True; int keySymbol = 0; int unmodifiedKeySymbol = 0; if (state) { event.type = KeyPress; adaptKey(event, keySymbol, unmodifiedKeySymbol); getEventQueue()->keyPress(keySymbol, time, unmodifiedKeySymbol); keyMapSetKey(_keyMap, key); } else { event.type = KeyRelease; adaptKey(event, keySymbol, unmodifiedKeySymbol); getEventQueue()->keyRelease(keySymbol, time, unmodifiedKeySymbol); keyMapClearKey(_keyMap, key); } } void GraphicsWindowX11::syncLocks() { unsigned int mask = getEventQueue()->getCurrentEventState()->getModKeyMask(); if (_modifierState & LockMask) mask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK; else mask &= ~osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK; if (_modifierState & _numLockMask) mask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK; else mask &= ~osgGA::GUIEventAdapter::MODKEY_NUM_LOCK; getEventQueue()->getCurrentEventState()->setModKeyMask(mask); } void GraphicsWindowX11::rescanModifierMapping() { XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay); KeyCode *m = mkm->modifiermap; KeyCode numlock = XKeysymToKeycode(_eventDisplay, XK_Num_Lock); _numLockMask = 0; for (int i = 0; i < mkm->max_keypermod * 8; i++, m++) { if (*m == numlock) { _numLockMask = 1 << (i / mkm->max_keypermod); break; } } XFree(mkm->modifiermap); XFree(mkm); } void GraphicsWindowX11::flushKeyEvents() { XEvent e; while (XCheckMaskEvent(_eventDisplay, KeyPressMask|KeyReleaseMask, &e)) continue; } // Returns char[32] keymap with bits for every modifier key set. void GraphicsWindowX11::getModifierMap(char* keymap) const { memset(keymap, 0, 32); XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay); KeyCode *m = mkm->modifiermap; for (int i = 0; i < mkm->max_keypermod * 8; i++, m++) { if (*m) keyMapSetKey(keymap, *m); } XFree(mkm->modifiermap); XFree(mkm); } int GraphicsWindowX11::getModifierMask() const { int mask = 0; XModifierKeymap *mkm = XGetModifierMapping(_eventDisplay); for (int i = 0; i < mkm->max_keypermod * 8; i++) { unsigned int key = mkm->modifiermap[i]; if (key && keyMapGetKey(_keyMap, key)) { mask |= 1 << (i / mkm->max_keypermod); } } XFree(mkm->modifiermap); XFree(mkm); return mask; } void GraphicsWindowX11::requestWarpPointer(float x,float y) { if (!_realized) { OSG_INFO<<"GraphicsWindowX11::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<(x), static_cast(y) ); XFlush(display); XSync(display, 0); getEventQueue()->mouseWarped(x,y); } extern "C" { typedef int (*X11ErrorHandler)(Display*, XErrorEvent*); int X11ErrorHandling(Display* display, XErrorEvent* event) { OSG_NOTICE<<"Got an X11ErrorHandling call display="<request_code << std::endl; OSG_NOTICE << "Minor opcode: " << (int)event->minor_code << std::endl; OSG_NOTICE << "Error code: " << (int)event->error_code << std::endl; OSG_NOTICE << "Request serial: " << event->serial << std::endl; OSG_NOTICE << "Current serial: " << NextRequest( display ) - 1 << std::endl; switch( event->error_code ) { case BadValue: OSG_NOTICE << " Value: " << event->resourceid << std::endl; break; case BadAtom: OSG_NOTICE << " AtomID: " << event->resourceid << std::endl; break; default: OSG_NOTICE << " ResourceID: " << event->resourceid << std::endl; break; } return 0; } } class X11WindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface { #ifdef OSGVIEWER_USE_XRANDR // TODO: Investigate whether or not Robert thinks we should store/restore the original // resolution in the destructor; I'm not sure the other ones do this, and it may be the // responsibility of the user. bool _setScreen(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height, unsigned int colorDepth, double rate) { if (colorDepth>0) OSG_NOTICE << "X11WindowingSystemInterface::_setScreen() is not fully implemented (missing depth)."<(width) && ss[i].height == static_cast(height)) { short* rates = XRRConfigRates(sc, i, &numRates); bool rateFound = false; // Search for our rate in the list of acceptable rates given to us by Xrandr. // If it's not found, rateFound will still be false and the call will never // be made to XRRSetScreenConfigAndRate since the rate will be invalid. for(int r = 0; r < numRates; r++) { if(rates[r] == static_cast(rate)) { rateFound = true; break; } } if(rate > 0.0f && !rateFound) { OSG_NOTICE << "Unable to find valid refresh rate " << rate << " on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<(rate), CurrentTime) != RRSetConfigSuccess) { OSG_NOTICE << "Unable to set resolution to " << width << "x" << height << " on display \"" << XDisplayName(si.displayName().c_str()) << "\"."<setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } //OSG_NOTICE<<"~X11WindowingSystemInterface()"< 1 || ( major == 1 && minor >= 2 ) ); } #endif return false; } virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution ) { Display* display = XOpenDisplay(si.displayName().c_str()); if(display) { resolution.width = DisplayWidth(display, si.screenNum); resolution.height = DisplayHeight(display, si.screenNum); resolution.colorDepth = DefaultDepth(display, si.screenNum); resolution.refreshRate = 0; // Missing call. Need a X11 expert. #ifdef OSGVIEWER_USE_XRANDR if (supportsRandr(display)) { XRRScreenConfiguration* screenConfig = XRRGetScreenInfo ( display, RootWindow(display, si.screenNum) ); resolution.refreshRate = XRRConfigCurrentRate ( screenConfig ); XRRFreeScreenConfigInfo( screenConfig ); } #endif XCloseDisplay(display); } else { OSG_NOTICE << "Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\"."<0) { for(int i=0; i0) { for(int j=0; jpbuffer) { #if 1 osg::ref_ptr pbuffer = new PixelBufferX11(traits); if (pbuffer->valid()) return pbuffer.release(); else return 0; #else osg::ref_ptr window = new GraphicsWindowX11(traits); if (window->valid()) return window.release(); else return 0; #endif } else { osg::ref_ptr window = new GraphicsWindowX11(traits); if (window->valid()) return window.release(); else return 0; } } }; struct RegisterWindowingSystemInterfaceProxy { RegisterWindowingSystemInterfaceProxy() { OSG_INFO<<"RegisterWindowingSystemInterfaceProxy()"<setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } osg::GraphicsContext::setWindowingSystemInterface(0); } }; RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy; // declare C entry point for static compilation. extern "C" void graphicswindow_X11(void) { osg::GraphicsContext::setWindowingSystemInterface(new X11WindowingSystemInterface); } void GraphicsWindowX11::raiseWindow() { Display* display = getDisplayToUse(); if(!display) return; // get handles to window props of interest Atom stateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", True); Atom stateAtom = XInternAtom(display, "_NET_WM_STATE", True); // check that atoms are supported if(stateAbove != None && stateAtom != None) { // fill an XEvent struct to send XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = _window; xev.xclient.message_type = stateAtom; xev.xclient.format = 32; xev.xclient.data.l[0] = 1; xev.xclient.data.l[1] = stateAbove; xev.xclient.data.l[2] = 0; XSendEvent(display, RootWindow(display, DefaultScreen(display)), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } else { // one or both of _NET_WM_STATE and _NET_WM_STATE_ABOVE aren't supported // try to use XRaiseWindow XWindowAttributes winAttrib; Window root_return, parent_return, *children; unsigned int nchildren, i=0; XTextProperty windowName; bool xraise = false; // get the window tree around our current window XQueryTree(display, _parent, &root_return, &parent_return, &children, &nchildren); while (!xraise && iwindowName.c_str(),(const char *)windowName.value) == 0)) xraise = true; } if (xraise) XRaiseWindow(display,_window); else { XGetWindowAttributes(display, _window, &winAttrib); XReparentWindow(display, _window, _parent, winAttrib.x, winAttrib.y); } XFree(children); } XFlush(display); XSync(display,0); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/DarwinUtils.mm0000644000175000017500000004727113151044751024436 0ustar albertoalberto/* * DarwinUtils.cpp * OpenSceneGraph * * Created by Stephan Huber on 27.06.08. * Copyright 2008 Stephan Maximilian Huber, digital mind. All rights reserved. * */ #include #include #include "DarwinUtils.h" #include #include @interface MenubarToggler : NSObject { osg::ref_ptr _displaySettings; osg::DisplaySettings::OSXMenubarBehavior _menubarBehavior; } -(void) show; -(void) hide; -(void) setDisplaySettings: (osg::DisplaySettings*) display_settings; @end @implementation MenubarToggler -(id) init { self = [super init]; _menubarBehavior = osg::DisplaySettings::MENUBAR_AUTO_HIDE; _displaySettings = NULL; return self; } -(void) setDisplaySettings: (osg::DisplaySettings*) display_settings { _displaySettings = display_settings; } -(void) hide { if(_displaySettings.valid()) _menubarBehavior = _displaySettings->getOSXMenubarBehavior(); if (_menubarBehavior == osg::DisplaySettings::MENUBAR_FORCE_SHOW) return; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 NSApplicationPresentationOptions options; switch(_menubarBehavior) { case osg::DisplaySettings::MENUBAR_AUTO_HIDE: options = NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock; break; case osg::DisplaySettings::MENUBAR_FORCE_HIDE: options = NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock; break; default: options = NSApplicationPresentationDefault; } [[NSApplication sharedApplication] setPresentationOptions: options]; #else SystemUIMode mode = kUIModeAllHidden; SystemUIOptions options = 0; switch(_menubarBehavior) { case osg::DisplaySettings::MENUBAR_AUTO_HIDE: options = kUIOptionAutoShowMenuBar; break; case osg::DisplaySettings::MENUBAR_FORCE_HIDE: break; default: mode = kUIModeNormal; } OSErr error = SetSystemUIMode(mode, options); if (error) { OSG_DEBUG << "MenubarToggler::hide failed with " << error << std::endl; } #endif } -(void) show { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 [[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationDefault]; #else OSErr error = SetSystemUIMode(kUIModeNormal, 0); if (error) { OSG_DEBUG << "MenubarToggler::show failed with " << error << std::endl; } #endif } @end namespace osgDarwin { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 size_t displayBitsPerPixelForMode(CGDisplayModeRef mode) { CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode); if (!pixEnc) { OSG_WARN << "CGDisplayModeCopyPixelEncoding returned NULL" << std::endl; CGDisplayModeRelease(mode); return 0; } size_t depth = 0; if (CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { depth = 32; } else if (CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { depth = 16; } else if (CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { depth = 8; } else { OSG_WARN << "Unable to match pixel encoding '" << CFStringGetCStringPtr(pixEnc, kCFStringEncodingUTF8) << "'" << std::endl; } CFRelease(pixEnc); return depth; } #endif size_t displayBitsPerPixel( CGDirectDisplayID displayId ) { #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 return CGDisplayBitsPerPixel(displayId); #else CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); if (!mode) { OSG_WARN << "CGDisplayCopyDisplayMode returned NULL" << std::endl; return 0; } unsigned int depth = displayBitsPerPixelForMode(mode); CGDisplayModeRelease(mode); return depth; #endif } static bool findBestDisplayModeFor(const CGDirectDisplayID& displayid, int desired_width, int desired_height, unsigned int desired_color_depth, double desired_refresh_rate) { CFArrayRef availableModes = CGDisplayCopyAllDisplayModes(displayid, NULL); unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes); CGDisplayModeRef best_match(NULL); int best_dx = std::numeric_limits::max(); int best_dy = std::numeric_limits::max(); for (unsigned int i=0; i 0) && (dx <= best_dx) && (dy > 0) && (dy <= best_dy) && (color_depth >= desired_color_depth) && (rate >= desired_refresh_rate)) { best_match = mode; best_dx = dx; best_dy = dy; } } bool result = false; if(best_match) { result = CGDisplaySetDisplayMode(displayid, best_match, NULL) != kCGErrorSuccess; } else if (desired_refresh_rate > 0) { // try again with a lower refresh-rate result = findBestDisplayModeFor(displayid, desired_width, desired_height, desired_color_depth, 0); } else if (desired_color_depth > 0) { // try again with a lower color_depth result = findBestDisplayModeFor(displayid, desired_width, desired_height, 0, 0); } CFRelease(availableModes); return result; } static inline CGRect toCGRect(NSRect nsRect) { CGRect cgRect; cgRect.origin.x = nsRect.origin.x; cgRect.origin.y = nsRect.origin.y; cgRect.size.width = nsRect.size.width; cgRect.size.height = nsRect.size.height; return cgRect; } MenubarController::MenubarController() : osg::Referenced(), _list(), _menubarShown(true), _mutex() { // the following code will query the system for the available rect on the main-display (typically the displaying showing the menubar + the dock NSRect rect = [[[NSScreen screens] objectAtIndex: 0] visibleFrame]; _availRect = toCGRect(rect); // now we need the rect of the main-display including the menubar and the dock _mainScreenBounds = CGDisplayBounds( CGMainDisplayID() ); // NSRect 0/0 is bottom/left, _mainScreenBounds 0/0 is top/left _availRect.origin.y = _mainScreenBounds.size.height - _availRect.size.height - _availRect.origin.y; _toggler = [[MenubarToggler alloc] init]; update(); } MenubarController::~MenubarController() { [_toggler release]; } void MenubarController::setDisplaySettings(osg::DisplaySettings* display_settings) { [_toggler setDisplaySettings:display_settings]; update(); } MenubarController* MenubarController::instance() { static osg::ref_ptr s_menubar_controller = new MenubarController(); return s_menubar_controller.get(); } void MenubarController::attachWindow(WindowAdapter* win) { OpenThreads::ScopedLock lock(_mutex); _list.push_back(win); update(); } void MenubarController::detachWindow(osgViewer::GraphicsWindow* win) { OpenThreads::ScopedLock lock(_mutex); for(WindowList::iterator i = _list.begin(); i != _list.end(); ) { if ((*i)->getWindow() == win) i = _list.erase(i); else ++i; } update(); } // iterate through all open windows and check, if they intersect the area occupied by the menubar/dock, and if so, hide the menubar/dock void MenubarController::update() { unsigned int windowsCoveringMenubarArea = 0; unsigned int windowsIntersectingMainScreen = 0; for(WindowList::iterator i = _list.begin(); i != _list.end(); ) { WindowAdapter* wi = (*i).get(); if (wi->valid()) { CGRect windowBounds; wi->getWindowBounds(windowBounds); if (CGRectIntersectsRect(_mainScreenBounds, windowBounds)) { ++windowsIntersectingMainScreen; // OSG_ALWAYS << "testing rect " << windowBounds.origin.x << "/" << windowBounds.origin.y << " " << windowBounds.size.width << "x" << windowBounds.size.height << std::endl; // OSG_ALWAYS << "against " << _availRect.origin.x << "/" << _availRect.origin.y << " " << _availRect.size.width << "x" << _availRect.size.height << std::endl; // the window intersects the main-screen, does it intersect with the menubar/dock? if (((_availRect.origin.y > _mainScreenBounds.origin.y) && (_availRect.origin.y > windowBounds.origin.y)) || ((_availRect.origin.x > _mainScreenBounds.origin.x) && (_availRect.origin.x > windowBounds.origin.x)) || ((_availRect.size.width < _mainScreenBounds.size.width) && (_availRect.origin.x + _availRect.size.width < windowBounds.origin.x + windowBounds.size.width)) || ((_availRect.size.height < _mainScreenBounds.size.height) && (_availRect.origin.y + _availRect.size.height < windowBounds.origin.y + windowBounds.size.height) )) { ++windowsCoveringMenubarArea; } } ++i; } else i = _list.erase(i); } // if we use the cocoa implementation then we have a NSRunLoop in place, and so we can use the deferred menubar-toggling which is thread safe #ifdef USE_DARWIN_COCOA_IMPLEMENTATION // SetSystemUIMode is not threadsafe, you'll get crashes if you call this method from other threads // so use a small NSObject to switch the menubar on the main thread via performSelectorOnMainThread NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; if (windowsCoveringMenubarArea && _menubarShown) { //error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); [_toggler performSelectorOnMainThread: @selector(hide) withObject:NULL waitUntilDone: YES]; } if (!windowsCoveringMenubarArea && !_menubarShown) { //error = SetSystemUIMode(kUIModeNormal, 0); [_toggler performSelectorOnMainThread: @selector(show) withObject:NULL waitUntilDone: YES]; } [pool release]; #else OSErr error; // see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar if (windowsCoveringMenubarArea && _menubarShown) { error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); } if (!windowsCoveringMenubarArea && !_menubarShown) { error = SetSystemUIMode(kUIModeNormal, 0); } #endif _menubarShown = !windowsCoveringMenubarArea; } /** Helper method to get a double value out of a CFDictionary */ static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) { double value; CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); if (!number_value) // if can't get a number for the dictionary return -1; // fail if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &value)) // or if cant convert it return -1; // fail return value; // otherwise return the long value } /** Helper method to get a long value out of a CFDictionary */ static long getDictLong(CFDictionaryRef refDict, CFStringRef key) // const void* key? { long value = 0; CFNumberRef number_value = (CFNumberRef)CFDictionaryGetValue(refDict, key); if (!number_value) // if can't get a number for the dictionary return -1; // fail if (!CFNumberGetValue(number_value, kCFNumberLongType, &value)) // or if cant convert it return -1; // fail return value; } /** ctor, get a list of all attached displays */ DarwinWindowingSystemInterface::DarwinWindowingSystemInterface() : _initialized(false), _displayCount(0), _displayIds(NULL) { } /** dtor */ DarwinWindowingSystemInterface::~DarwinWindowingSystemInterface() { if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } if (_displayIds) delete[] _displayIds; _displayIds = NULL; } void DarwinWindowingSystemInterface::_init() { if (_initialized) return; ProcessSerialNumber sn = { 0, kCurrentProcess }; TransformProcessType(&sn,kProcessTransformToForegroundApplication); SetFrontProcess(&sn); if( CGGetActiveDisplayList( 0, NULL, &_displayCount ) != CGDisplayNoErr ) { OSG_WARN << "DarwinWindowingSystemInterface: could not get # of screens" << std::endl; _displayCount = 0; _initialized = true; return; } _displayIds = new CGDirectDisplayID[_displayCount]; if( CGGetActiveDisplayList( _displayCount, _displayIds, &_displayCount ) != CGDisplayNoErr ) { OSG_WARN << "DarwinWindowingSystemInterface: CGGetActiveDisplayList failed" << std::endl; } _initialized = true; } /** @return a CGDirectDisplayID for a ScreenIdentifier */ CGDirectDisplayID DarwinWindowingSystemInterface::getDisplayID(const osg::GraphicsContext::ScreenIdentifier& si) { _init(); if (_displayCount==0) { OSG_WARN << "DarwinWindowingSystemInterface::getDisplayID(..) no valid screens available returning 0 instead." << std::endl; return 0; } if (si.screenNum < static_cast(_displayCount)) { return _displayIds[si.screenNum]; } else { OSG_WARN << "DarwinWindowingSystemInterface::getDisplayID(..) invalid screen # " << si.screenNum << ", returning main-screen instead." << std::endl; return _displayIds[0]; } } /** @return count of attached screens */ unsigned int DarwinWindowingSystemInterface::getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si) { _init(); return _displayCount; } void DarwinWindowingSystemInterface::getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution) { _init(); if (_displayCount==0) { resolution.width = 0; resolution.height = 0; resolution.colorDepth = 0; resolution.refreshRate = 0; return; } CGDirectDisplayID id = getDisplayID(si); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 CGDisplayModeRef display_mode_ref = CGDisplayCopyDisplayMode(id); resolution.width = CGDisplayModeGetWidth(display_mode_ref); resolution.height = CGDisplayModeGetHeight(display_mode_ref); resolution.colorDepth = displayBitsPerPixelForMode(display_mode_ref); resolution.refreshRate = CGDisplayModeGetRefreshRate(display_mode_ref); CGDisplayModeRelease(display_mode_ref); #else resolution.width = CGDisplayPixelsWide(id); resolution.height = CGDisplayPixelsHigh(id); resolution.colorDepth = displayBitsPerPixel(id); resolution.refreshRate = getDictDouble (CGDisplayCurrentMode(id), kCGDisplayRefreshRate); // Not tested #endif if (resolution.refreshRate<0) resolution.refreshRate = 0; } void DarwinWindowingSystemInterface::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList) { _init(); // Warning! This method has not been tested. resolutionList.clear(); if (_displayCount==0) { return; } CGDirectDisplayID displayid = getDisplayID(screenIdentifier); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 CFArrayRef availableModes = CGDisplayCopyAllDisplayModes(displayid, NULL); unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes); for (unsigned int i=0; i(bounds.origin.x); y = static_cast(bounds.origin.y); // OSG_DEBUG << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl; } bool DarwinWindowingSystemInterface::setScreenSettings(const osg::GraphicsContext::ScreenIdentifier &si, const osg::GraphicsContext::ScreenSettings & settings) { CGDirectDisplayID displayid = getDisplayID(si); #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060) return findBestDisplayModeFor(displayid, settings.width, settings.height, settings.colorDepth, settings.refreshRate); #else // add next line and on following line replace hard coded depth and refresh rate CGRefreshRate refresh = getDictDouble (CGDisplayCurrentMode(displayid), kCGDisplayRefreshRate); CFDictionaryRef display_mode_values = CGDisplayBestModeForParametersAndRefreshRate( displayid, settings.colorDepth, settings.width, settings.height, settings.refreshRate, NULL); return CGDisplaySwitchToMode(displayid, display_mode_values) != kCGErrorSuccess; #endif return false; } unsigned int DarwinWindowingSystemInterface::getScreenContaining(int x, int y, int w, int h) { _init(); if (_displayCount==0) { return 0; } CGRect rect = CGRectMake(x,y,w,h); for(unsigned int i = 0; i < _displayCount; ++i) { CGRect bounds = CGDisplayBounds( getDisplayID(i) ); if (CGRectIntersectsRect(bounds, rect)) { return i; } } return 0; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/Scene.cpp0000644000175000017500000000717113151044751023372 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgViewer; namespace osgViewer { struct SceneSingleton { SceneSingleton() {} inline void add(Scene* scene) { OpenThreads::ScopedLock lock(_mutex); _cache.push_back(scene); } inline void remove(Scene* scene) { OpenThreads::ScopedLock lock(_mutex); for(SceneCache::iterator itr = _cache.begin(); itr != _cache.end(); ++itr) { if (scene==itr->get()) { _cache.erase(itr); break; } } } inline Scene* getScene(osg::Node* node) { OpenThreads::ScopedLock lock(_mutex); for(SceneCache::iterator itr = _cache.begin(); itr != _cache.end(); ++itr) { Scene* scene = itr->get(); if (scene && scene->getSceneData()==node) return scene; } return 0; } typedef std::vector< osg::observer_ptr > SceneCache; SceneCache _cache; OpenThreads::Mutex _mutex; }; static SceneSingleton& getSceneSingleton() { static SceneSingleton s_sceneSingleton; return s_sceneSingleton; } // Use a proxy to force the initialization of the SceneSingleton during static initialization OSG_INIT_SINGLETON_PROXY(SceneSingletonProxy, getSceneSingleton()) } Scene::Scene(): osg::Referenced(true) { setDatabasePager(osgDB::DatabasePager::create()); setImagePager(new osgDB::ImagePager); getSceneSingleton().add(this); } Scene::~Scene() { getSceneSingleton().remove(this); } void Scene::setSceneData(osg::Node* node) { _sceneData = node; } osg::Node* Scene::getSceneData() { return _sceneData.get(); } const osg::Node* Scene::getSceneData() const { return _sceneData.get(); } void Scene::setDatabasePager(osgDB::DatabasePager* dp) { _databasePager = dp; } void Scene::setImagePager(osgDB::ImagePager* ip) { _imagePager = ip; } void Scene::updateSceneGraph(osg::NodeVisitor& updateVisitor) { if (!_sceneData) return; if (getDatabasePager()) { // synchronize changes required by the DatabasePager thread to the scene graph getDatabasePager()->updateSceneGraph((*updateVisitor.getFrameStamp())); } if (getImagePager()) { // synchronize changes required by the DatabasePager thread to the scene graph getImagePager()->updateSceneGraph(*(updateVisitor.getFrameStamp())); } if (getSceneData()) { updateVisitor.setImageRequestHandler(getImagePager()); getSceneData()->accept(updateVisitor); } } Scene* Scene::getScene(osg::Node* node) { return getSceneSingleton().getScene(node); return 0; } Scene* Scene::getOrCreateScene(osg::Node* node) { if (!node) return 0; osgViewer::Scene* scene = getScene(node); if (!scene) { scene = new Scene; scene->setSceneData(node); } return scene; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/HelpHandler.cpp0000644000175000017500000001422113151044751024515 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include using namespace osgViewer; HelpHandler::HelpHandler(osg::ApplicationUsage* au): _applicationUsage(au), _keyEventTogglesOnScreenHelp('h'), _helpEnabled(false), _initialized(false) { _camera = new osg::Camera; _camera->setRenderer(new Renderer(_camera.get())); _camera->setRenderOrder(osg::Camera::POST_RENDER, 11); } void HelpHandler::reset() { _initialized = false; _camera->setGraphicsContext(0); } bool HelpHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { osgViewer::View* view = dynamic_cast(&aa); if (!view) return false; osgViewer::ViewerBase* viewer = view->getViewerBase(); if (!viewer) return false; if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): { if (ea.getKey()==_keyEventTogglesOnScreenHelp) { if (!_initialized) { setUpHUDCamera(viewer); setUpScene(viewer); } _helpEnabled = !_helpEnabled; if (_helpEnabled) { _camera->setNodeMask(0xffffffff); } else { _camera->setNodeMask(0); } return true; } } default: break; } return false; } void HelpHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer) { osgViewer::GraphicsWindow* window = dynamic_cast(_camera->getGraphicsContext()); if (!window) { osgViewer::Viewer::Windows windows; viewer->getWindows(windows); if (windows.empty()) return; window = windows.front(); _camera->setGraphicsContext(window); } _camera->setGraphicsContext(window); _camera->setViewport(0, 0, window->getTraits()->width, window->getTraits()->height); _camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024)); _camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); _camera->setViewMatrix(osg::Matrix::identity()); // only clear the depth buffer _camera->setClearMask(0); _initialized = true; } void HelpHandler::setUpScene(osgViewer::ViewerBase* viewer) { _switch = new osg::Switch; _camera->addChild(_switch.get()); osg::StateSet* stateset = _switch->getOrCreateStateSet(); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); stateset->setMode(GL_BLEND,osg::StateAttribute::ON); stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF); stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED); std::string font("fonts/arial.ttf"); if (!_applicationUsage) setApplicationUsage(new osg::ApplicationUsage()); viewer->getUsage(*_applicationUsage); float leftPos = 10.0f; float startDescription = 200.0f; float characterSize = 20.0f; osg::Vec3 pos(leftPos,1000.0f,0.0f); osg::Vec4 color(1.0f,1.0f,1.0f,1.0f); osg::Geode* geode = new osg::Geode(); _switch->addChild(geode, true); // application description if (!_applicationUsage->getDescription().empty()) { osg::ref_ptr label = new osgText::Text; geode->addDrawable( label.get() ); label->setColor(color); label->setBackdropType(osgText::Text::OUTLINE); label->setFont(font); label->setCharacterSize(characterSize); label->setPosition(pos); label->setText(_applicationUsage->getDescription()); pos.x() = label->getBoundingBox().xMax(); pos.y() -= characterSize*2.5f; } const osg::ApplicationUsage::UsageMap& keyboardBinding = _applicationUsage->getKeyboardMouseBindings(); for(osg::ApplicationUsage::UsageMap::const_iterator itr = keyboardBinding.begin(); itr != keyboardBinding.end(); ++itr) { pos.x() = leftPos; osg::ref_ptr key = new osgText::Text; geode->addDrawable( key.get() ); key->setColor(color); key->setBackdropType(osgText::Text::OUTLINE); key->setFont(font); key->setCharacterSize(characterSize); key->setPosition(pos); key->setText(itr->first); pos.x() = startDescription; osg::ref_ptr description = new osgText::Text; geode->addDrawable( description.get() ); description->setColor(color); description->setBackdropType(osgText::Text::OUTLINE); description->setFont(font); description->setCharacterSize(characterSize); description->setPosition(pos); description->setText(itr->second); pos.y() -= characterSize*1.5f; } osg::BoundingBox bb = geode->getBoundingBox(); if (bb.valid()) { float width = bb.xMax() - bb.xMin(); float height = bb.yMax() - bb.yMin(); float ratio = 1.0; if (width > 1024.0f) ratio = 1024.0f/width; if (height*ratio > 800.0f) ratio = 800.0f/height; _camera->setViewMatrix(osg::Matrix::translate(-bb.center()) * osg::Matrix::scale(ratio,ratio,ratio) * osg::Matrix::translate(osg::Vec3(640.0f, 520.0f, 0.0f))); } } void HelpHandler::getUsage(osg::ApplicationUsage& usage) const { if (_keyEventTogglesOnScreenHelp) usage.addKeyboardMouseBinding(_keyEventTogglesOnScreenHelp,"Onscreen help."); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/ScreenCaptureHandler.cpp0000644000175000017500000007101013151044751026367 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include namespace osgViewer { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // WindowCaptureCallback // // From osgscreencapture example /** Callback which will be added to a viewer's camera to do the actual screen capture. */ class WindowCaptureCallback : public osg::Camera::DrawCallback { public: enum Mode { READ_PIXELS, SINGLE_PBO, DOUBLE_PBO, TRIPLE_PBO }; enum FramePosition { START_FRAME, END_FRAME }; WindowCaptureCallback(int numFrames, Mode mode, FramePosition position, GLenum readBuffer); FramePosition getFramePosition() const { return _position; } void setCaptureOperation(ScreenCaptureHandler::CaptureOperation* operation); ScreenCaptureHandler::CaptureOperation* getCaptureOperation() { return _contextDataMap.begin()->second->_captureOperation.get(); } void setFramesToCapture(int numFrames) { _numFrames = numFrames; } int getFramesToCapture() const { return _numFrames; } virtual void operator () (osg::RenderInfo& renderInfo) const; struct OSGVIEWER_EXPORT ContextData : public osg::Referenced { ContextData(osg::GraphicsContext* gc, Mode mode, GLenum readBuffer); void getSize(osg::GraphicsContext* gc, int& width, int& height); void updateTimings(osg::Timer_t tick_start, osg::Timer_t tick_afterReadPixels, osg::Timer_t tick_afterMemCpy, osg::Timer_t tick_afterCaptureOperation, unsigned int dataSize); void read(); void readPixels(); void singlePBO(osg::GLExtensions* ext); void multiPBO(osg::GLExtensions* ext); typedef std::vector< osg::ref_ptr > ImageBuffer; typedef std::vector< GLuint > PBOBuffer; osg::GraphicsContext* _gc; unsigned int _index; Mode _mode; GLenum _readBuffer; GLenum _pixelFormat; GLenum _type; int _width; int _height; unsigned int _currentImageIndex; ImageBuffer _imageBuffer; unsigned int _currentPboIndex; PBOBuffer _pboBuffer; unsigned int _reportTimingFrequency; unsigned int _numTimeValuesRecorded; double _timeForReadPixels; double _timeForMemCpy; double _timeForCaptureOperation; double _timeForFullCopy; double _timeForFullCopyAndOperation; osg::Timer_t _previousFrameTick; osg::ref_ptr _captureOperation; }; typedef std::map > ContextDataMap; ContextData* createContextData(osg::GraphicsContext* gc) const; ContextData* getContextData(osg::GraphicsContext* gc) const; Mode _mode; FramePosition _position; GLenum _readBuffer; mutable OpenThreads::Mutex _mutex; mutable ContextDataMap _contextDataMap; mutable int _numFrames; osg::ref_ptr _defaultCaptureOperation; }; WindowCaptureCallback::ContextData::ContextData(osg::GraphicsContext* gc, Mode mode, GLenum readBuffer) : _gc(gc), _index(_gc->getState()->getContextID()), _mode(mode), _readBuffer(readBuffer), _pixelFormat(GL_RGBA), _type(GL_UNSIGNED_BYTE), _width(0), _height(0), _currentImageIndex(0), _currentPboIndex(0), _reportTimingFrequency(100), _numTimeValuesRecorded(0), _timeForReadPixels(0.0), _timeForMemCpy(0.0), _timeForCaptureOperation(0.0), _timeForFullCopy(0.0), _timeForFullCopyAndOperation(0.0), _previousFrameTick(0) { _previousFrameTick = osg::Timer::instance()->tick(); osg::NotifySeverity level = osg::INFO; if (gc->getTraits()) { if (gc->getTraits()->alpha) { OSG_NOTIFY(level)<<"ScreenCaptureHandler: Selected GL_RGBA read back format"<getTraits()) { width = gc->getTraits()->width; height = gc->getTraits()->height; } } void WindowCaptureCallback::ContextData::updateTimings(osg::Timer_t tick_start, osg::Timer_t tick_afterReadPixels, osg::Timer_t tick_afterMemCpy, osg::Timer_t tick_afterCaptureOperation, unsigned int /*dataSize*/) { _timeForReadPixels = osg::Timer::instance()->delta_s(tick_start, tick_afterReadPixels); _timeForMemCpy = osg::Timer::instance()->delta_s(tick_afterReadPixels, tick_afterMemCpy); _timeForCaptureOperation = osg::Timer::instance()->delta_s(tick_afterMemCpy, tick_afterCaptureOperation); _timeForFullCopy = osg::Timer::instance()->delta_s(tick_start, tick_afterMemCpy); _timeForFullCopyAndOperation = osg::Timer::instance()->delta_s(tick_start, tick_afterCaptureOperation); } void WindowCaptureCallback::ContextData::read() { osg::GLExtensions* ext = osg::GLExtensions::Get(_gc->getState()->getContextID(),true); if (ext->isPBOSupported && !_pboBuffer.empty()) { if (_pboBuffer.size()==1) { singlePBO(ext); } else { multiPBO(ext); } } else { readPixels(); } } void WindowCaptureCallback::ContextData::readPixels() { unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size(); unsigned int nextPboIndex = _pboBuffer.empty() ? 0 : (_currentPboIndex+1)%_pboBuffer.size(); int width=0, height=0; getSize(_gc, width, height); if (width!=_width || _height!=height) { //OSG_NOTICE<<" Window resized "<tick(); #if 1 image->readPixels(0,0,_width,_height, _pixelFormat,_type); #endif osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick(); if (_captureOperation.valid()) { (*_captureOperation)(*image, _index); } osg::Timer_t tick_afterCaptureOperation = osg::Timer::instance()->tick(); updateTimings(tick_start, tick_afterReadPixels, tick_afterReadPixels, tick_afterCaptureOperation, image->getTotalSizeInBytes()); _currentImageIndex = nextImageIndex; _currentPboIndex = nextPboIndex; } void WindowCaptureCallback::ContextData::singlePBO(osg::GLExtensions* ext) { unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size(); int width=0, height=0; getSize(_gc, width, height); if (width!=_width || _height!=height) { //OSG_NOTICE<<" Window resized "<s() != _width || image->t() != _height) { //OSG_NOTICE<<"ScreenCaptureHandler: Allocating image "<allocateImage(_width, _height, 1, _pixelFormat, _type); if (pbo!=0) { //OSG_NOTICE<<"ScreenCaptureHandler: deleting pbo "<glDeleteBuffers (1, &pbo); pbo = 0; } } if (pbo==0) { ext->glGenBuffers(1, &pbo); ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ); //OSG_NOTICE<<"ScreenCaptureHandler: Generating pbo "<glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); } osg::Timer_t tick_start = osg::Timer::instance()->tick(); #if 1 glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0); #endif osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick(); GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); if(src) { memcpy(image->data(), src, image->getTotalSizeInBytes()); ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); } ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); osg::Timer_t tick_afterMemCpy = osg::Timer::instance()->tick(); if (_captureOperation.valid()) { (*_captureOperation)(*image, _index); } osg::Timer_t tick_afterCaptureOperation = osg::Timer::instance()->tick(); updateTimings(tick_start, tick_afterReadPixels, tick_afterMemCpy, tick_afterCaptureOperation, image->getTotalSizeInBytes()); _currentImageIndex = nextImageIndex; } void WindowCaptureCallback::ContextData::multiPBO(osg::GLExtensions* ext) { unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size(); unsigned int nextPboIndex = (_currentPboIndex+1)%_pboBuffer.size(); int width=0, height=0; getSize(_gc, width, height); if (width!=_width || _height!=height) { //OSG_NOTICE<<" Window resized "<s() != _width || image->t() != _height) { //OSG_NOTICE<<"ScreenCaptureHandler: Allocating image "<allocateImage(_width, _height, 1, _pixelFormat, _type); if (read_pbo!=0) { //OSG_NOTICE<<"ScreenCaptureHandler: deleting pbo "<glDeleteBuffers (1, &read_pbo); read_pbo = 0; } if (copy_pbo!=0) { //OSG_NOTICE<<"ScreenCaptureHandler: deleting pbo "<glDeleteBuffers (1, ©_pbo); copy_pbo = 0; } } bool doCopy = copy_pbo!=0; if (copy_pbo==0) { ext->glGenBuffers(1, ©_pbo); ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo); ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ); //OSG_NOTICE<<"ScreenCaptureHandler: Generating pbo "<glGenBuffers(1, &read_pbo); ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo); ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ); //OSG_NOTICE<<"ScreenCaptureHandler: Generating pbo "<glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo); } osg::Timer_t tick_start = osg::Timer::instance()->tick(); #if 1 glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0); #endif osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick(); if (doCopy) { ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo); GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); if(src) { memcpy(image->data(), src, image->getTotalSizeInBytes()); ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); } if (_captureOperation.valid()) { (*_captureOperation)(*image, _index); } } ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); osg::Timer_t tick_afterMemCpy = osg::Timer::instance()->tick(); updateTimings(tick_start, tick_afterReadPixels, tick_afterMemCpy, tick_afterMemCpy, image->getTotalSizeInBytes()); _currentImageIndex = nextImageIndex; _currentPboIndex = nextPboIndex; } WindowCaptureCallback::WindowCaptureCallback(int numFrames, Mode mode, FramePosition position, GLenum readBuffer) : _mode(mode), _position(position), _readBuffer(readBuffer), _numFrames(numFrames) { } WindowCaptureCallback::ContextData* WindowCaptureCallback::createContextData(osg::GraphicsContext* gc) const { WindowCaptureCallback::ContextData* cd = new WindowCaptureCallback::ContextData(gc, _mode, _readBuffer); cd->_captureOperation = _defaultCaptureOperation; return cd; } WindowCaptureCallback::ContextData* WindowCaptureCallback::getContextData(osg::GraphicsContext* gc) const { OpenThreads::ScopedLock lock(_mutex); osg::ref_ptr& data = _contextDataMap[gc]; if (!data) data = createContextData(gc); return data.get(); } void WindowCaptureCallback::setCaptureOperation(ScreenCaptureHandler::CaptureOperation* operation) { _defaultCaptureOperation = operation; // Set the capture operation for each ContextData. for (ContextDataMap::iterator it = _contextDataMap.begin(); it != _contextDataMap.end(); ++it) { it->second->_captureOperation = operation; } } void WindowCaptureCallback::operator () (osg::RenderInfo& renderInfo) const { #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) glReadBuffer(_readBuffer); #endif osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext(); osg::ref_ptr cd = getContextData(gc); cd->read(); // If _numFrames is > 0 it means capture that number of frames. if (_numFrames > 0) { --_numFrames; if (_numFrames == 0) { // the callback must remove itself when it's done. if (_position == START_FRAME) renderInfo.getCurrentCamera()->setInitialDrawCallback(0); if (_position == END_FRAME) renderInfo.getCurrentCamera()->setFinalDrawCallback(0); } } int prec = osg::notify(osg::INFO).precision(5); OSG_INFO << "ScreenCaptureHandler: " << "copy=" << (cd->_timeForFullCopy*1000.0f) << "ms, " << "operation=" << (cd->_timeForCaptureOperation*1000.0f) << "ms, " << "total=" << (cd->_timeForFullCopyAndOperation*1000.0f) << std::endl; osg::notify(osg::INFO).precision(prec); cd->_timeForFullCopy = 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ScreenCaptureHandler::WriteToFile // ScreenCaptureHandler::WriteToFile::WriteToFile(const std::string& filename, const std::string& extension, SavePolicy savePolicy) : _filename(filename), _extension(extension), _savePolicy(savePolicy) { } void ScreenCaptureHandler::WriteToFile::operator () (const osg::Image& image, const unsigned int context_id) { if (_savePolicy == SEQUENTIAL_NUMBER) { if (_contextSaveCounter.size() <= context_id) { unsigned int oldSize = _contextSaveCounter.size(); _contextSaveCounter.resize(context_id + 1); // Initialize all new values to 0 since context ids may not be consecutive. for (unsigned int i = oldSize; i <= context_id; i++) _contextSaveCounter[i] = 0; } } std::stringstream filename; filename << _filename << "_" << context_id; if (_savePolicy == SEQUENTIAL_NUMBER) filename << "_" << _contextSaveCounter[context_id]; filename << "." << _extension; osgDB::writeImageFile(image, filename.str()); OSG_INFO<<"ScreenCaptureHandler: Taking a screenshot, saved as '"<(_callback.get()); callback->setCaptureOperation(operation); } ScreenCaptureHandler::CaptureOperation* ScreenCaptureHandler::getCaptureOperation() const { WindowCaptureCallback* callback = static_cast(_callback.get()); return callback->getCaptureOperation(); } void ScreenCaptureHandler::addCallbackToViewer(osgViewer::ViewerBase& viewer) { osg::Camera* camera = findAppropriateCameraForCallback(viewer); if (!camera) return; WindowCaptureCallback* callback = static_cast(_callback.get()); if (callback && callback->getFramePosition() == WindowCaptureCallback::START_FRAME) { camera->setInitialDrawCallback(_callback.get()); } else { camera->setFinalDrawCallback(_callback.get()); } } void ScreenCaptureHandler::removeCallbackFromViewer(osgViewer::ViewerBase& viewer) { osg::Camera* camera = findAppropriateCameraForCallback(viewer); if (!camera) return; WindowCaptureCallback* callback = static_cast(_callback.get()); if (callback && callback->getFramePosition() == WindowCaptureCallback::START_FRAME) { camera->setInitialDrawCallback(0); } else { camera->setFinalDrawCallback(0); } } osg::Camera* ScreenCaptureHandler::findAppropriateCameraForCallback(osgViewer::ViewerBase& viewer) { // Select either the first or the last active camera, depending on the // frame position set in the callback. // One case where testing the node mask is important is when the stats // handler has been initialized, but stats are not displayed. In that // case, there is a post render camera on the viewer, but its node mask // is zero, so the callback added to that camera would never be called. WindowCaptureCallback* callback = static_cast(_callback.get()); if (callback->getFramePosition() == WindowCaptureCallback::START_FRAME) { osgViewer::ViewerBase::Contexts contexts; viewer.getContexts(contexts); for(osgViewer::ViewerBase::Contexts::iterator itr = contexts.begin(); itr != contexts.end(); ++itr) { osg::GraphicsContext* context = *itr; osg::GraphicsContext::Cameras& cameras = context->getCameras(); osg::Camera* firstCamera = 0; for(osg::GraphicsContext::Cameras::iterator cam_itr = cameras.begin(); cam_itr != cameras.end(); ++cam_itr) { if (firstCamera) { if ((*cam_itr)->getRenderOrder() < firstCamera->getRenderOrder()) { if ((*cam_itr)->getNodeMask() != 0x0) firstCamera = (*cam_itr); } if ((*cam_itr)->getRenderOrder() == firstCamera->getRenderOrder() && (*cam_itr)->getRenderOrderNum() < firstCamera->getRenderOrderNum()) { if ((*cam_itr)->getNodeMask() != 0x0) firstCamera = (*cam_itr); } } else { if ((*cam_itr)->getNodeMask() != 0x0) firstCamera = *cam_itr; } } if (firstCamera) { //OSG_NOTICE<<"ScreenCaptureHandler: First camera "<getCameras(); osg::Camera* lastCamera = 0; for(osg::GraphicsContext::Cameras::iterator cam_itr = cameras.begin(); cam_itr != cameras.end(); ++cam_itr) { if (lastCamera) { if ((*cam_itr)->getRenderOrder() > lastCamera->getRenderOrder()) { if ((*cam_itr)->getNodeMask() != 0x0) lastCamera = (*cam_itr); } if ((*cam_itr)->getRenderOrder() == lastCamera->getRenderOrder() && (*cam_itr)->getRenderOrderNum() >= lastCamera->getRenderOrderNum()) { if ((*cam_itr)->getNodeMask() != 0x0) lastCamera = (*cam_itr); } } else { if ((*cam_itr)->getNodeMask() != 0x0) lastCamera = *cam_itr; } } if (lastCamera) { //OSG_NOTICE<<"ScreenCaptureHandler: Last camera "<(&aa)->getViewerBase(); if (!viewer) return false; switch(ea.getEventType()) { case (osgGA::GUIEventAdapter::FRAME): { // Booleans aren't the best way of doing this, but I want to do // the actual adding here because I don't want to require // startCapture() take a viewer as argument, which could not be // the right one. if (_startCapture) { // Start capturing with the currently set number of frames. // If set to -1 it will capture continuously, if set to >0 // it will capture that number of frames. _startCapture = false; addCallbackToViewer(*viewer); } else if (_stopCapture) { _stopCapture = false; removeCallbackFromViewer(*viewer); } break; } case(osgGA::GUIEventAdapter::KEYUP): { if (ea.getKey() == _keyEventTakeScreenShot) { // Check that we will capture at least one frame. // Just check for ==0, because >0 is means we're already // capturing and <0 means it will capture all frames. WindowCaptureCallback* callback = static_cast(_callback.get()); if (callback->getFramesToCapture() == 0) { setFramesToCapture(1); } addCallbackToViewer(*viewer); return true; } if (ea.getKey() == _keyEventToggleContinuousCapture) { if (getFramesToCapture() < 0) { setFramesToCapture(0); removeCallbackFromViewer(*viewer); } else { setFramesToCapture(-1); addCallbackToViewer(*viewer); } return true; } break; } default: break; } return false; } /** Capture the given viewer's views on the next frame. */ void ScreenCaptureHandler::captureNextFrame(osgViewer::ViewerBase& viewer) { addCallbackToViewer(viewer); } /** Set the number of frames to capture. */ void ScreenCaptureHandler::setFramesToCapture(int numFrames) { WindowCaptureCallback* callback = static_cast(_callback.get()); callback->setFramesToCapture(numFrames); } /** Get the number of frames to capture. */ int ScreenCaptureHandler::getFramesToCapture() const { WindowCaptureCallback* callback = static_cast(_callback.get()); return callback->getFramesToCapture(); } /** Start capturing at the end of the next frame. */ void ScreenCaptureHandler::startCapture() { if (getFramesToCapture() != 0) _startCapture = true; } /** Stop capturing. */ void ScreenCaptureHandler::stopCapture() { _stopCapture = true; } /** Get the keyboard and mouse usage of this manipulator.*/ void ScreenCaptureHandler::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding(_keyEventTakeScreenShot,"Take screenshot."); usage.addKeyboardMouseBinding(_keyEventToggleContinuousCapture,"Toggle continuous screen capture."); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/ViewerBase.cpp0000644000175000017500000007213013151044751024366 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static osg::ApplicationUsageProxy ViewerBase_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CONFIG_FILE ","Specify a viewer configuration file to load by default."); static osg::ApplicationUsageProxy ViewerBase_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING ","Set the threading model using by Viewer, can be SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or CullThreadPerCameraDrawThreadPerContext."); static osg::ApplicationUsageProxy ViewerBase_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN ","Set the default screen that windows should open up on."); static osg::ApplicationUsageProxy ViewerBase_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y width height","Set the default window dimensions that windows should open up on."); static osg::ApplicationUsageProxy ViewerBase_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_FRAME_SCHEME","Frame rate manage scheme that viewer run should use, ON_DEMAND or CONTINUOUS (default)."); static osg::ApplicationUsageProxy ViewerBase_e5(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_MAX_FRAME_RATE","Set the maximum number of frame as second that viewer run. 0.0 is default and disables an frame rate capping."); using namespace osgViewer; ViewerBase::ViewerBase(): osg::Object(true) { viewerBaseInit(); } ViewerBase::ViewerBase(const ViewerBase&): osg::Object(true) { viewerBaseInit(); } void ViewerBase::viewerBaseInit() { _firstFrame = true; _done = false; _keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape; _quitEventSetsDone = true; _releaseContextAtEndOfFrameHint = true; _threadingModel = AutomaticSelection; _threadsRunning = false; _endBarrierPosition = AfterSwapBuffers; _endBarrierOperation = osg::BarrierOperation::NO_OPERATION; _requestRedraw = true; _requestContinousUpdate = false; _runFrameScheme = CONTINUOUS; _runMaxFrameRate = 0.0f; const char* str = getenv("OSG_RUN_FRAME_SCHEME"); if (str) { if (strcmp(str, "ON_DEMAND")==0) _runFrameScheme = ON_DEMAND; else if (strcmp(str, "CONTINUOUS")==0) _runFrameScheme = CONTINUOUS; } str = getenv("OSG_RUN_MAX_FRAME_RATE"); if (str) { _runMaxFrameRate = osg::asciiToDouble(str); } } void ViewerBase::setThreadingModel(ThreadingModel threadingModel) { if (_threadingModel == threadingModel) return; if (_threadsRunning) stopThreading(); _threadingModel = threadingModel; if (isRealized() && _threadingModel!=SingleThreaded) startThreading(); } ViewerBase::ThreadingModel ViewerBase::suggestBestThreadingModel() { const char* str = getenv("OSG_THREADING"); if (str) { if (strcmp(str,"SingleThreaded")==0) return SingleThreaded; else if (strcmp(str,"CullDrawThreadPerContext")==0) return CullDrawThreadPerContext; else if (strcmp(str,"DrawThreadPerContext")==0) return DrawThreadPerContext; else if (strcmp(str,"CullThreadPerCameraDrawThreadPerContext")==0) return CullThreadPerCameraDrawThreadPerContext; } Contexts contexts; getContexts(contexts); if (contexts.empty()) return SingleThreaded; #if 0 // temporary hack to disable multi-threading under Windows till we find good solutions for // crashes that users are seeing. return SingleThreaded; #endif Cameras cameras; getCameras(cameras); if (cameras.empty()) return SingleThreaded; int numProcessors = OpenThreads::GetNumberOfProcessors(); if (contexts.size()==1) { if (numProcessors==1) return SingleThreaded; else return DrawThreadPerContext; } #if 1 if (numProcessors >= static_cast(cameras.size()+contexts.size())) { return CullThreadPerCameraDrawThreadPerContext; } #endif return DrawThreadPerContext; } void ViewerBase::setUpThreading() { Contexts contexts; getContexts(contexts); if (_threadingModel==SingleThreaded) { if (_threadsRunning) stopThreading(); else { // we'll set processor affinity here to help single threaded apps // with multiple processor cores, and using the database pager. int numProcessors = OpenThreads::GetNumberOfProcessors(); bool affinity = numProcessors>1; if (affinity) { OpenThreads::SetProcessorAffinityOfCurrentThread(0); Scenes scenes; getScenes(scenes); for(Scenes::iterator scitr = scenes.begin(); scitr != scenes.end(); ++scitr) { if ((*scitr)->getSceneData()) { // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it. (*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts()); } } } } } else { if (!_threadsRunning) startThreading(); } } void ViewerBase::setEndBarrierPosition(BarrierPosition bp) { if (_endBarrierPosition == bp) return; if (_threadsRunning) stopThreading(); _endBarrierPosition = bp; if (_threadingModel!=SingleThreaded) startThreading(); } void ViewerBase::setEndBarrierOperation(osg::BarrierOperation::PreBlockOp op) { if (_endBarrierOperation == op) return; if (_threadsRunning) stopThreading(); _endBarrierOperation = op; if (_threadingModel!=SingleThreaded) startThreading(); } void ViewerBase::stopThreading() { if (!_threadsRunning) return; OSG_INFO<<"ViewerBase::stopThreading() - stopping threading"<(camera->getRenderer()); if (renderer) renderer->release(); } // delete all the graphics threads. for(gcitr = contexts.begin(); gcitr != contexts.end(); ++gcitr) { (*gcitr)->setGraphicsThread(0); } // delete all the camera threads. for(citr = cameras.begin(); citr != cameras.end(); ++citr) { (*citr)->setCameraThread(0); } for(Cameras::iterator camItr = cameras.begin(); camItr != cameras.end(); ++camItr) { osg::Camera* camera = *camItr; Renderer* renderer = dynamic_cast(camera->getRenderer()); if (renderer) { renderer->setGraphicsThreadDoesCull( true ); renderer->setDone(false); } } _threadsRunning = false; _startRenderingBarrier = 0; _endRenderingDispatchBarrier = 0; _endDynamicDrawBlock = 0; OSG_INFO<<"Viewer::stopThreading() - stopped threading."<getSceneData()) { OSG_INFO<<"Making scene thread safe"<getSceneData()->setThreadSafeRefUnref(true); // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it. (*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts()); } } int numProcessors = OpenThreads::GetNumberOfProcessors(); bool affinity = numProcessors>1; Contexts::iterator citr; unsigned int numViewerDoubleBufferedRenderingOperation = 0; bool graphicsThreadsDoesCull = _threadingModel == CullDrawThreadPerContext || _threadingModel==SingleThreaded; for(Cameras::iterator camItr = cameras.begin(); camItr != cameras.end(); ++camItr) { osg::Camera* camera = *camItr; Renderer* renderer = dynamic_cast(camera->getRenderer()); if (renderer) { renderer->setGraphicsThreadDoesCull(graphicsThreadsDoesCull); renderer->setDone(false); renderer->reset(); ++numViewerDoubleBufferedRenderingOperation; } } if (_threadingModel==CullDrawThreadPerContext) { _startRenderingBarrier = 0; _endRenderingDispatchBarrier = 0; _endDynamicDrawBlock = 0; } else if (_threadingModel==DrawThreadPerContext || _threadingModel==CullThreadPerCameraDrawThreadPerContext) { _startRenderingBarrier = 0; _endRenderingDispatchBarrier = 0; _endDynamicDrawBlock = new osg::EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation); #ifndef OSGUTIL_RENDERBACKEND_USE_REF_PTR if (!osg::Referenced::getDeleteHandler()) osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2)); else osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(2); #endif } if (numThreadsOnStartBarrier>1) { _startRenderingBarrier = new osg::BarrierOperation(numThreadsOnStartBarrier, osg::BarrierOperation::NO_OPERATION); } if (numThreadsOnEndBarrier>1) { _endRenderingDispatchBarrier = new osg::BarrierOperation(numThreadsOnEndBarrier, _endBarrierOperation); } osg::ref_ptr swapReadyBarrier = contexts.empty() ? 0 : new osg::BarrierOperation(contexts.size(), osg::BarrierOperation::NO_OPERATION); osg::ref_ptr swapOp = new osg::SwapBuffersOperation(); typedef std::map ThreadAffinityMap; ThreadAffinityMap threadAffinityMap; unsigned int processNum = 1; for(citr = contexts.begin(); citr != contexts.end(); ++citr, ++processNum) { osg::GraphicsContext* gc = (*citr); if (!gc->isRealized()) { OSG_INFO<<"ViewerBase::startThreading() : Realizng window "<realize(); } gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get()); // create the a graphics thread for this context gc->createGraphicsThread(); if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors); threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors; // add the startRenderingBarrier if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get()); // add the rendering operation itself. gc->getGraphicsThread()->add(new osg::RunOperations()); if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid()) { // add the endRenderingDispatchBarrier gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); } if (swapReadyBarrier.valid()) gc->getGraphicsThread()->add(swapReadyBarrier.get()); // add the swap buffers gc->getGraphicsThread()->add(swapOp.get()); if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid()) { // add the endRenderingDispatchBarrier gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); } } if (_threadingModel==CullThreadPerCameraDrawThreadPerContext && numThreadsOnStartBarrier>1) { Cameras::iterator camItr; for(camItr = cameras.begin(); camItr != cameras.end(); ++camItr, ++processNum) { osg::Camera* camera = *camItr; camera->createCameraThread(); if (affinity) camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors); threadAffinityMap[camera->getCameraThread()] = processNum % numProcessors; osg::GraphicsContext* gc = camera->getGraphicsContext(); // add the startRenderingBarrier if (_startRenderingBarrier.valid()) camera->getCameraThread()->add(_startRenderingBarrier.get()); Renderer* renderer = dynamic_cast(camera->getRenderer()); renderer->setGraphicsThreadDoesCull(false); camera->getCameraThread()->add(renderer); if (_endRenderingDispatchBarrier.valid()) { // add the endRenderingDispatchBarrier gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); } } for(camItr = cameras.begin(); camItr != cameras.end(); ++camItr) { osg::Camera* camera = *camItr; if (camera->getCameraThread() && !camera->getCameraThread()->isRunning()) { OSG_INFO<<" camera->getCameraThread()-> "<getCameraThread()<getCameraThread()->startThread(); } } } #if 0 if (affinity) { OpenThreads::SetProcessorAffinityOfCurrentThread(0); if (_scene.valid() && _scene->getDatabasePager()) { #if 0 _scene->getDatabasePager()->setProcessorAffinity(1); #else _scene->getDatabasePager()->setProcessorAffinity(0); #endif } } #endif #if 0 if (affinity) { for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin(); titr != threadAffinityMap.end(); ++titr) { titr->first->setProcessorAffinity(titr->second); } } #endif for(citr = contexts.begin(); citr != contexts.end(); ++citr) { osg::GraphicsContext* gc = (*citr); if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning()) { OSG_INFO<<" gc->getGraphicsThread()->startThread() "<getGraphicsThread()<getGraphicsThread()->startThread(); // OpenThreads::Thread::YieldCurrentThread(); } } _threadsRunning = true; OSG_INFO<<"Set up threading"<(*itr); if (gw) windows.push_back(gw); } } void ViewerBase::checkWindowStatus() { Contexts contexts; getContexts(contexts); checkWindowStatus(contexts); } void ViewerBase::checkWindowStatus(const Contexts& contexts) { if (contexts.size()==0) { _done = true; if (areThreadsRunning()) stopThreading(); } } void ViewerBase::addUpdateOperation(osg::Operation* operation) { if (!operation) return; if (!_updateOperations) _updateOperations = new osg::OperationQueue; _updateOperations->add(operation); } void ViewerBase::removeUpdateOperation(osg::Operation* operation) { if (!operation) return; if (_updateOperations.valid()) { _updateOperations->remove(operation); } } void ViewerBase::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico) { if (_incrementalCompileOperation == ico) return; Contexts contexts; getContexts(contexts, false); if (_incrementalCompileOperation.valid()) _incrementalCompileOperation->removeContexts(contexts); // assign new operation _incrementalCompileOperation = ico; Scenes scenes; getScenes(scenes,false); for(Scenes::iterator itr = scenes.begin(); itr != scenes.end(); ++itr) { osgDB::DatabasePager* dp = (*itr)->getDatabasePager(); dp->setIncrementalCompileOperation(ico); } if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); } int ViewerBase::run() { if (!isRealized()) { realize(); } const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT"); unsigned int runTillFrameNumber = run_frame_count_str==0 ? osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str); while(!done() && (run_frame_count_str==0 || getViewerFrameStamp()->getFrameNumber()0.0 ? 1.0/_runMaxFrameRate : 0.0; osg::Timer_t startFrameTick = osg::Timer::instance()->tick(); if (_runFrameScheme==ON_DEMAND) { if (checkNeedToDoFrame()) { frame(); } else { // we don't need to render a frame but we don't want to spin the run loop so make sure the minimum // loop time is 1/100th of second, if not otherwise set, so enabling the frame microSleep below to // avoid consume excessive CPU resources. if (minFrameTime==0.0) minFrameTime=0.01; } } else { frame(); } // work out if we need to force a sleep to hold back the frame rate osg::Timer_t endFrameTick = osg::Timer::instance()->tick(); double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick); if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(static_cast(1000000.0*(minFrameTime-frameTime))); } return 0; } void ViewerBase::frame(double simulationTime) { if (_done) return; // OSG_NOTICE<getCamera()->getInverseViewMatrix(); OSG_NOTICE<<"View "<collectStats("scene")) { unsigned int frameNumber = frameStamp ? frameStamp->getFrameNumber() : 0; Views views; getViews(views); for(Views::iterator vitr = views.begin(); vitr != views.end(); ++vitr) { View* view = *vitr; osg::Stats* stats = view->getStats(); osg::Node* sceneRoot = view->getSceneData(); if (sceneRoot && stats) { osgUtil::StatsVisitor statsVisitor; sceneRoot->accept(statsVisitor); statsVisitor.totalUpStats(); unsigned int unique_primitives = 0; osgUtil::Statistics::PrimitiveCountMap::iterator pcmitr; for(pcmitr = statsVisitor._uniqueStats.GetPrimitivesBegin(); pcmitr != statsVisitor._uniqueStats.GetPrimitivesEnd(); ++pcmitr) { unique_primitives += pcmitr->second; } stats->setAttribute(frameNumber, "Number of unique StateSet", static_cast(statsVisitor._statesetSet.size())); stats->setAttribute(frameNumber, "Number of unique Group", static_cast(statsVisitor._groupSet.size())); stats->setAttribute(frameNumber, "Number of unique Transform", static_cast(statsVisitor._transformSet.size())); stats->setAttribute(frameNumber, "Number of unique LOD", static_cast(statsVisitor._lodSet.size())); stats->setAttribute(frameNumber, "Number of unique Switch", static_cast(statsVisitor._switchSet.size())); stats->setAttribute(frameNumber, "Number of unique Geode", static_cast(statsVisitor._geodeSet.size())); stats->setAttribute(frameNumber, "Number of unique Drawable", static_cast(statsVisitor._drawableSet.size())); stats->setAttribute(frameNumber, "Number of unique Geometry", static_cast(statsVisitor._geometrySet.size())); stats->setAttribute(frameNumber, "Number of unique Vertices", static_cast(statsVisitor._uniqueStats._vertexCount)); stats->setAttribute(frameNumber, "Number of unique Primitives", static_cast(unique_primitives)); unsigned int instanced_primitives = 0; for(pcmitr = statsVisitor._instancedStats.GetPrimitivesBegin(); pcmitr != statsVisitor._instancedStats.GetPrimitivesEnd(); ++pcmitr) { instanced_primitives += pcmitr->second; } stats->setAttribute(frameNumber, "Number of instanced Stateset", static_cast(statsVisitor._numInstancedStateSet)); stats->setAttribute(frameNumber, "Number of instanced Group", static_cast(statsVisitor._numInstancedGroup)); stats->setAttribute(frameNumber, "Number of instanced Transform", static_cast(statsVisitor._numInstancedTransform)); stats->setAttribute(frameNumber, "Number of instanced LOD", static_cast(statsVisitor._numInstancedLOD)); stats->setAttribute(frameNumber, "Number of instanced Switch", static_cast(statsVisitor._numInstancedSwitch)); stats->setAttribute(frameNumber, "Number of instanced Geode", static_cast(statsVisitor._numInstancedGeode)); stats->setAttribute(frameNumber, "Number of instanced Drawable", static_cast(statsVisitor._numInstancedDrawable)); stats->setAttribute(frameNumber, "Number of instanced Geometry", static_cast(statsVisitor._numInstancedGeometry)); stats->setAttribute(frameNumber, "Number of instanced Vertices", static_cast(statsVisitor._instancedStats._vertexCount)); stats->setAttribute(frameNumber, "Number of instanced Primitives", static_cast(instanced_primitives)); } } } Scenes scenes; getScenes(scenes); for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0; if (dp) dp->signalBeginFrame(frameStamp); osgDB::ImagePager* ip = scene ? scene->getImagePager() : 0; if (ip) ip->signalBeginFrame(frameStamp); if (scene->getSceneData()) { // fire off a build of the bounding volumes while we // are still running single threaded. scene->getSceneData()->getBound(); } } // OSG_NOTICE<reset(); } // dispatch the rendering threads if (_startRenderingBarrier.valid()) _startRenderingBarrier->block(); // reset any double buffer graphics objects for(Cameras::iterator camItr = cameras.begin(); camItr != cameras.end(); ++camItr) { osg::Camera* camera = *camItr; Renderer* renderer = dynamic_cast(camera->getRenderer()); if (renderer) { if (!renderer->getGraphicsThreadDoesCull() && !(camera->getCameraThread())) { renderer->cull(); } } } for(itr = contexts.begin(); itr != contexts.end() && !_done; ++itr) { if (!((*itr)->getGraphicsThread()) && (*itr)->valid()) { doneMakeCurrentInThisThread = true; makeCurrent(*itr); (*itr)->runOperations(); } } // OSG_NOTICE<<"Joing _endRenderingDispatchBarrier block "<<_endRenderingDispatchBarrier.get()<block(); for(itr = contexts.begin(); itr != contexts.end() && !_done; ++itr) { if (!((*itr)->getGraphicsThread()) && (*itr)->valid()) { doneMakeCurrentInThisThread = true; makeCurrent(*itr); (*itr)->swapBuffers(); } } for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0; if (dp) dp->signalEndFrame(); osgDB::ImagePager* ip = scene ? scene->getImagePager() : 0; if (ip) ip->signalEndFrame(); } // wait till the dynamic draw is complete. if (_endDynamicDrawBlock.valid()) { // osg::Timer_t startTick = osg::Timer::instance()->tick(); _endDynamicDrawBlock->block(); // OSG_NOTICE<<"Time waiting "<delta_m(startTick, osg::Timer::instance()->tick())<collectStats("update")) { double endRenderingTraversals = elapsedTime(); // update current frames stats getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals begin time ", beginRenderingTraversals); getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals); getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals); } _requestRedraw = false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/IOSUtils.h0000644000175000017500000000713613151044751023456 0ustar albertoalberto/* * IOSUtils.h * OpenSceneGraph * * Created by Thomas Hogarth on 25.11.09. * * By default we create a full res buffer across all devices and if now viewContentScaleFator is given We use the screens ScaleFactor. * This means that for backward compatibility you need to set the windowData _viewContentScaleFactor to 1.0f and set the screen res to the * res that of the older gen device. * http://developer.apple.com/library/ios/documentation/IOS/Conceptual/IOSOSProgrammingGuide/SupportingResolutionIndependence/SupportingResolutionIndependence.html#//apple_ref/doc/uid/TP40007072-CH10-SW11 * */ #ifdef __APPLE__ #ifndef IOS_UTILS_HEADER_ #define IOS_UTILS_HEADER_ #ifdef __OBJC__ @class UIScreen; #else class UIScreen; #endif #include #include #include namespace osgIOS { struct IOSWindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface { public: IOSWindowingSystemInterface(); /** dtor */ ~IOSWindowingSystemInterface(); /** @return count of attached screens */ virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si) ; virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution); virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList); virtual bool setScreenSettings (const osg::GraphicsContext::ScreenIdentifier & si, const osg::GraphicsContext::ScreenSettings & settings); /** returns screen-ndx containing rect x,y,w,h, NOT_TESTED@tom */ unsigned int getScreenContaining(int x, int y, int w, int h); //IOS specific // //return the UIScreen object asscoiated with the passed ScreenIdentifier //returns nil if si isn't found UIScreen* getUIScreen(const osg::GraphicsContext::ScreenIdentifier& si); // //Get the contents scale factor of the screen, this is the scale factor required //to convert points to pixels on this screen bool getScreenContentScaleFactor(const osg::GraphicsContext::ScreenIdentifier& si, float& scaleFactor); // //Get the screens size in points, docs state a point is roughly 1/160th of an inch bool getScreenSizeInPoints(const osg::GraphicsContext::ScreenIdentifier& si, osg::Vec2& pointSize); protected: /** implementation of setScreenResolution */ //IPad can have extenal screens which we can request a res for //the main screen screenNum 0 can not currently have its res changed //as it only has one mode (might change though and this should still handle it) bool setScreenResolutionImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height); /** implementation of setScreenRefreshRate, currently can't set refresh rate of IOS*/ bool setScreenRefreshRateImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate); private: }; template struct RegisterWindowingSystemInterfaceProxy { RegisterWindowingSystemInterfaceProxy() { osg::GraphicsContext::setWindowingSystemInterface(new WSI); } ~RegisterWindowingSystemInterfaceProxy() { if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } osg::GraphicsContext::setWindowingSystemInterface(0); } }; } #endif #endif // __APPLE__ OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/View.cpp0000644000175000017500000023751413151044751023255 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // view configurations. #include #include #include #include #include #include #include using namespace osgViewer; osg::DisplaySettings* ViewConfig::getActiveDisplaySetting(osgViewer::View& view) const { return view.getDisplaySettings() ? view.getDisplaySettings() : osg::DisplaySettings::instance().get(); } class CollectedCoordinateSystemNodesVisitor : public osg::NodeVisitor { public: CollectedCoordinateSystemNodesVisitor(): NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) {} META_NodeVisitor("osgViewer","CollectedCoordinateSystemNodesVisitor") virtual void apply(osg::Node& node) { traverse(node); } virtual void apply(osg::CoordinateSystemNode& node) { if (_pathToCoordinateSystemNode.empty()) { OSG_DEBUG<<"Found CoordinateSystemNode node"<getCoordinateSystemNodePath(); if (!tmpPath.empty()) { osg::Matrixd coordinateFrame; osg::CoordinateSystemNode* csn = dynamic_cast(tmpPath.back()); if (csn) { osg::Vec3 local_position = position*osg::computeWorldToLocal(tmpPath); // get the coordinate frame in world coords. coordinateFrame = csn->computeLocalCoordinateFrame(local_position)* osg::computeLocalToWorld(tmpPath); // keep the position of the coordinate frame to reapply after rescale. osg::Vec3d pos = coordinateFrame.getTrans(); // compensate for any scaling, so that the coordinate frame is a unit size osg::Vec3d x(1.0,0.0,0.0); osg::Vec3d y(0.0,1.0,0.0); osg::Vec3d z(0.0,0.0,1.0); x = osg::Matrixd::transform3x3(x,coordinateFrame); y = osg::Matrixd::transform3x3(y,coordinateFrame); z = osg::Matrixd::transform3x3(z,coordinateFrame); coordinateFrame.preMultScale(osg::Vec3d(1.0/x.length(),1.0/y.length(),1.0/z.length())); // reapply the position. coordinateFrame.setTrans(pos); OSG_DEBUG<<"csn->computeLocalCoordinateFrame(position)* osg::computeLocalToWorld(tmpPath)"< _view; }; View::View(): _fusionDistanceMode(osgUtil::SceneView::PROPORTIONAL_TO_SCREEN_DISTANCE), _fusionDistanceValue(1.0f) { // OSG_NOTICE<<"Constructing osgViewer::View"<setFrameNumber(0); _frameStamp->setReferenceTime(0); _frameStamp->setSimulationTime(0); _scene = new Scene; // make sure View is safe to reference multi-threaded. setThreadSafeRefUnref(true); // need to attach a Renderer to the master camera which has been default constructed getCamera()->setRenderer(createRenderer(getCamera())); setEventQueue(new osgGA::EventQueue); setStats(new osg::Stats("View")); } View::View(const osgViewer::View& view, const osg::CopyOp& copyop): osg::Object(true), osg::View(view,copyop), osgGA::GUIActionAdapter(), _startTick(0), _fusionDistanceMode(view._fusionDistanceMode), _fusionDistanceValue(view._fusionDistanceValue) { _scene = new Scene; // need to attach a Renderer to the master camera which has been default constructed getCamera()->setRenderer(createRenderer(getCamera())); setEventQueue(new osgGA::EventQueue); setStats(new osg::Stats("View")); } View::~View() { OSG_INFO<<"Destructing osgViewer::View"<(&rhs); if (rhs_osgViewer) { // copy across rhs _startTick = rhs_osgViewer->_startTick; _frameStamp = rhs_osgViewer->_frameStamp; if (rhs_osgViewer->getSceneData()) { _scene = rhs_osgViewer->_scene; } if (rhs_osgViewer->_cameraManipulator.valid()) { _cameraManipulator = rhs_osgViewer->_cameraManipulator; } _eventHandlers.insert(_eventHandlers.end(), rhs_osgViewer->_eventHandlers.begin(), rhs_osgViewer->_eventHandlers.end()); _coordinateSystemNodePath = rhs_osgViewer->_coordinateSystemNodePath; _displaySettings = rhs_osgViewer->_displaySettings; _fusionDistanceMode = rhs_osgViewer->_fusionDistanceMode; _fusionDistanceValue = rhs_osgViewer->_fusionDistanceValue; // clear rhs rhs_osgViewer->_frameStamp = 0; rhs_osgViewer->_scene = 0; rhs_osgViewer->_cameraManipulator = 0; rhs_osgViewer->_eventHandlers.clear(); rhs_osgViewer->_coordinateSystemNodePath.clearNodePath(); rhs_osgViewer->_displaySettings = 0; } #endif computeActiveCoordinateSystemNodePath(); assignSceneDataToCameras(); } osg::GraphicsOperation* View::createRenderer(osg::Camera* camera) { Renderer* render = new Renderer(camera); camera->setStats(new osg::Stats("Camera")); return render; } void View::init() { OSG_INFO<<"View::init()"< initEvent = _eventQueue->createEvent(); initEvent->setEventType(osgGA::GUIEventAdapter::FRAME); if (_cameraManipulator.valid()) { _cameraManipulator->init(*initEvent, *this); } } void View::setStartTick(osg::Timer_t tick) { _startTick = tick; for(Devices::iterator eitr = _eventSources.begin(); eitr != _eventSources.end(); ++eitr) { (*eitr)->getEventQueue()->setStartTick(_startTick); } } void View::setSceneData(osg::Node* node) { if (node==_scene->getSceneData()) return; osg::ref_ptr scene = Scene::getScene(node); if (scene) { OSG_INFO<<"View::setSceneData() Sharing scene "<referenceCount()!=1) { // we are not the only reference to the Scene so we cannot reuse it. _scene = new Scene; OSG_INFO<<"View::setSceneData() Allocating new scene"<<_scene.get()<setSceneData(node); } if (getSceneData()) { #if defined(OSG_GLES2_AVAILABLE) osgUtil::ShaderGenVisitor sgv; getSceneData()->getOrCreateStateSet(); getSceneData()->accept(sgv); #endif // now make sure the scene graph is set up with the correct DataVariance to protect the dynamic elements of // the scene graph from being run in parallel. osgUtil::Optimizer::StaticObjectDetectionVisitor sodv; getSceneData()->accept(sodv); // make sure that existing scene graph objects are allocated with thread safe ref/unref if (getViewerBase() && getViewerBase()->getThreadingModel()!=ViewerBase::SingleThreaded) { getSceneData()->setThreadSafeRefUnref(true); } // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it. getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts()); } computeActiveCoordinateSystemNodePath(); assignSceneDataToCameras(); } void View::setDatabasePager(osgDB::DatabasePager* dp) { _scene->setDatabasePager(dp); } osgDB::DatabasePager* View::getDatabasePager() { return _scene->getDatabasePager(); } const osgDB::DatabasePager* View::getDatabasePager() const { return _scene->getDatabasePager(); } void View::setImagePager(osgDB::ImagePager* dp) { _scene->setImagePager(dp); } osgDB::ImagePager* View::getImagePager() { return _scene->getImagePager(); } const osgDB::ImagePager* View::getImagePager() const { return _scene->getImagePager(); } void View::setCameraManipulator(osgGA::CameraManipulator* manipulator, bool resetPosition) { _cameraManipulator = manipulator; if (_cameraManipulator.valid()) { _cameraManipulator->setCoordinateFrameCallback(new ViewerCoordinateFrameCallback(this)); if (getSceneData()) _cameraManipulator->setNode(getSceneData()); if (resetPosition) { osg::ref_ptr dummyEvent = _eventQueue->createEvent(); _cameraManipulator->home(*dummyEvent, *this); } } } void View::home() { if (_cameraManipulator.valid()) { osg::ref_ptr dummyEvent = _eventQueue->createEvent(); _cameraManipulator->home(*dummyEvent, *this); } } void View::addEventHandler(osgGA::EventHandler* eventHandler) { EventHandlers::iterator itr = std::find(_eventHandlers.begin(), _eventHandlers.end(), eventHandler); if (itr == _eventHandlers.end()) { _eventHandlers.push_back(eventHandler); } } void View::removeEventHandler(osgGA::EventHandler* eventHandler) { EventHandlers::iterator itr = std::find(_eventHandlers.begin(), _eventHandlers.end(), eventHandler); if (itr != _eventHandlers.end()) { _eventHandlers.erase(itr); } } void View::setCoordinateSystemNodePath(const osg::NodePath& nodePath) { _coordinateSystemNodePath.setNodePath(nodePath); } osg::NodePath View::getCoordinateSystemNodePath() const { osg::NodePath nodePath; _coordinateSystemNodePath.getNodePath(nodePath); return nodePath; } void View::computeActiveCoordinateSystemNodePath() { // now search for CoordinateSystemNode's for which we want to track. osg::Node* subgraph = getSceneData(); if (subgraph) { CollectedCoordinateSystemNodesVisitor ccsnv; subgraph->accept(ccsnv); if (!ccsnv._pathToCoordinateSystemNode.empty()) { setCoordinateSystemNodePath(ccsnv._pathToCoordinateSystemNode); return; } } // otherwise no node path found so reset to empty. setCoordinateSystemNodePath(osg::NodePath()); } void View::apply(ViewConfig* config) { if (config) { OSG_INFO<<"Applying osgViewer::ViewConfig : "<className()<configure(*this); } _lastAppliedViewConfig = config; } void View::setUpViewAcrossAllScreens() { apply(new osgViewer::AcrossAllScreens()); } void View::setUpViewInWindow(int x, int y, int width, int height, unsigned int screenNum) { apply(new osgViewer::SingleWindow(x, y, width, height, screenNum)); } void View::setUpViewOnSingleScreen(unsigned int screenNum) { apply(new osgViewer::SingleScreen(screenNum)); } void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned int screenNum, osg::Image* intensityMap, const osg::Matrixd& projectorMatrix) { apply(new osgViewer::SphericalDisplay(radius, collar, screenNum, intensityMap, projectorMatrix)); } void View::setUpViewForPanoramicSphericalDisplay(double radius, double collar, unsigned int screenNum, osg::Image* intensityMap, const osg::Matrixd& projectorMatrix) { apply(new osgViewer::PanoramicSphericalDisplay(radius, collar, screenNum, intensityMap, projectorMatrix)); } void View::setUpViewForWoWVxDisplay(unsigned int screenNum, unsigned char wow_content, unsigned char wow_factor, unsigned char wow_offset, float wow_disparity_Zd, float wow_disparity_vz, float wow_disparity_M, float wow_disparity_C) { apply(new osgViewer::WoWVxDisplay(screenNum, wow_content, wow_factor, wow_offset, wow_disparity_Zd,wow_disparity_vz, wow_disparity_M, wow_disparity_C)); } DepthPartitionSettings::DepthPartitionSettings(DepthMode mode): _mode(mode), _zNear(1.0), _zMid(5.0), _zFar(1000.0) {} bool DepthPartitionSettings::getDepthRange(osg::View& view, unsigned int partition, double& zNear, double& zFar) { switch(_mode) { case(FIXED_RANGE): { if (partition==0) { zNear = _zNear; zFar = _zMid; return true; } else if (partition==1) { zNear = _zMid; zFar = _zFar; return true; } return false; } case(BOUNDING_VOLUME): { osgViewer::View* view_withSceneData = dynamic_cast(&view); const osg::Node* node = view_withSceneData ? view_withSceneData->getSceneData() : 0; if (!node) return false; const osg::Camera* masterCamera = view.getCamera(); if (!masterCamera) return false; osg::BoundingSphere bs = node->getBound(); const osg::Matrixd& viewMatrix = masterCamera->getViewMatrix(); //osg::Matrixd& projectionMatrix = masterCamera->getProjectionMatrix(); osg::Vec3d lookVectorInWorldCoords = osg::Matrixd::transform3x3(viewMatrix,osg::Vec3d(0.0,0.0,-1.0)); lookVectorInWorldCoords.normalize(); osg::Vec3d nearPointInWorldCoords = bs.center() - lookVectorInWorldCoords*bs.radius(); osg::Vec3d farPointInWorldCoords = bs.center() + lookVectorInWorldCoords*bs.radius(); osg::Vec3d nearPointInEyeCoords = nearPointInWorldCoords * viewMatrix; osg::Vec3d farPointInEyeCoords = farPointInWorldCoords * viewMatrix; #if 0 OSG_NOTICE<setNodeMask(0x0); return; } else { camera->setNodeMask(0xffffff); } if (camera->getProjectionMatrix()(0,3)==0.0 && camera->getProjectionMatrix()(1,3)==0.0 && camera->getProjectionMatrix()(2,3)==0.0) { double left, right, bottom, top, zNear, zFar; camera->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar); camera->setProjectionMatrixAsOrtho(left, right, bottom, top, computed_zNear, computed_zFar); } else { double left, right, bottom, top, zNear, zFar; camera->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar); double nr = computed_zNear / zNear; camera->setProjectionMatrixAsFrustum(left * nr, right * nr, bottom * nr, top * nr, computed_zNear, computed_zFar); } } osg::ref_ptr _dps; unsigned int _partition; }; typedef std::list< osg::ref_ptr > Cameras; Cameras getActiveCameras(osg::View& view) { Cameras activeCameras; if (view.getCamera() && view.getCamera()->getGraphicsContext()) { activeCameras.push_back(view.getCamera()); } for(unsigned int i=0; igetGraphicsContext()) { activeCameras.push_back(slave._camera.get()); } } return activeCameras; } } bool View::setUpDepthPartitionForCamera(osg::Camera* cameraToPartition, DepthPartitionSettings* incoming_dps) { osg::ref_ptr context = cameraToPartition->getGraphicsContext(); if (!context) return false; osg::ref_ptr viewport = cameraToPartition->getViewport(); if (!viewport) return false; osg::ref_ptr dps = incoming_dps; if (!dps) dps = new DepthPartitionSettings; bool useMastersSceneData = true; osg::Matrixd projectionOffset; osg::Matrixd viewOffset; if (getCamera()==cameraToPartition) { // replace main camera with depth partition cameras OSG_INFO<<"View::setUpDepthPartitionForCamera(..) Replacing main Camera"<=getNumSlaves()) return false; osg::View::Slave& slave = getSlave(i); useMastersSceneData = slave._useMastersSceneData; projectionOffset = slave._projectionOffset; viewOffset = slave._viewOffset; OSG_NOTICE<<"View::setUpDepthPartitionForCamera(..) Replacing slave Camera"<setGraphicsContext(0); cameraToPartition->setViewport(0); // far camera { osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(context.get()); camera->setViewport(viewport.get()); camera->setDrawBuffer(cameraToPartition->getDrawBuffer()); camera->setReadBuffer(cameraToPartition->getReadBuffer()); camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); camera->setCullingMode(osg::Camera::ENABLE_ALL_CULLING); addSlave(camera.get()); osg::View::Slave& slave = getSlave(getNumSlaves()-1); slave._useMastersSceneData = useMastersSceneData; slave._projectionOffset = projectionOffset; slave._viewOffset = viewOffset; slave._updateSlaveCallback = new osgDepthPartition::MyUpdateSlaveCallback(dps.get(), 1); } // near camera { osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(context.get()); camera->setViewport(viewport.get()); camera->setDrawBuffer(cameraToPartition->getDrawBuffer()); camera->setReadBuffer(cameraToPartition->getReadBuffer()); camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); camera->setCullingMode(osg::Camera::ENABLE_ALL_CULLING); camera->setClearMask(GL_DEPTH_BUFFER_BIT); addSlave(camera.get()); osg::View::Slave& slave = getSlave(getNumSlaves()-1); slave._useMastersSceneData = useMastersSceneData; slave._projectionOffset = projectionOffset; slave._viewOffset = viewOffset; slave._updateSlaveCallback = new osgDepthPartition::MyUpdateSlaveCallback(dps.get(), 0); } return true; } bool View::setUpDepthPartition(DepthPartitionSettings* dsp) { osgDepthPartition::Cameras originalCameras = osgDepthPartition::getActiveCameras(*this); if (originalCameras.empty()) { OSG_INFO<<"osgView::View::setUpDepthPartition(,..), no windows assigned, doing view.setUpViewAcrossAllScreens()"<areThreadsRunning(); if (threadsWereRunning) getViewerBase()->stopThreading(); for(osgDepthPartition::Cameras::iterator itr = originalCameras.begin(); itr != originalCameras.end(); ++itr) { setUpDepthPartitionForCamera(itr->get(), dsp); } if (threadsWereRunning) getViewerBase()->startThreading(); return true; } void View::assignSceneDataToCameras() { // OSG_NOTICE<<"View::assignSceneDataToCameras()"<getDatabasePager() && getViewerBase()) { _scene->getDatabasePager()->setIncrementalCompileOperation(getViewerBase()->getIncrementalCompileOperation()); } osg::Node* sceneData = _scene.valid() ? _scene->getSceneData() : 0; if (_cameraManipulator.valid()) { _cameraManipulator->setNode(sceneData); osg::ref_ptr dummyEvent = _eventQueue->createEvent(); _cameraManipulator->home(*dummyEvent, *this); } if (_camera.valid()) { _camera->removeChildren(0,_camera->getNumChildren()); if (sceneData) _camera->addChild(sceneData); Renderer* renderer = dynamic_cast(_camera->getRenderer()); if (renderer) renderer->setCompileOnNextDraw(true); } for(unsigned i=0; iremoveChildren(0,slave._camera->getNumChildren()); if (sceneData) slave._camera->addChild(sceneData); Renderer* renderer = dynamic_cast(slave._camera->getRenderer()); if (renderer) renderer->setCompileOnNextDraw(true); } } } void View::requestRedraw() { if (getViewerBase()) { getViewerBase()->_requestRedraw = true; } else { OSG_INFO<<"View::requestRedraw(), No viewer base has been assigned yet."<_requestContinousUpdate = flag; } else { OSG_INFO<<"View::requestContinuousUpdate(), No viewer base has been assigned yet."<(camera->getGraphicsContext()); if (gw) { getEventQueue()->mouseWarped(x,y); if (gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) { local_y = gw->getTraits()->height - local_y; } const_cast(gw)->getEventQueue()->mouseWarped(local_x,local_y); const_cast(gw)->requestWarpPointer(local_x, local_y); } } else { OSG_INFO<<"View::requestWarpPointer failed no camera containing pointer"<getCurrentEventState(); const osgViewer::GraphicsWindow* gw = dynamic_cast(eventState->getGraphicsContext()); bool view_invert_y = eventState->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; // OSG_NOTICE<<"getCameraContainingPosition("<getViewport(); // rescale mouse x,y first to 0 to 1 range double new_x = (x-eventState->getXmin())/(eventState->getXmax()-eventState->getXmin()); double new_y = (y-eventState->getYmin())/(eventState->getYmax()-eventState->getYmin()); // flip y if required if (view_invert_y) new_y = 1.0f-new_y; // rescale mouse x, y to window dimensions so we can check against master Camera's viewport new_x *= static_cast(_camera->getGraphicsContext()->getTraits()->width); new_y *= static_cast(_camera->getGraphicsContext()->getTraits()->height); if (new_x >= (viewport->x()-epsilon) && new_y >= (viewport->y()-epsilon) && new_x < (viewport->x()+viewport->width()-1.0+epsilon) && new_y <= (viewport->y()+viewport->height()-1.0+epsilon) ) { local_x = new_x; local_y = new_y; //OSG_NOTICE<<"Returning master camera"<getViewMatrix() * getCamera()->getProjectionMatrix(); // convert to non dimensional x = (x - eventState->getXmin()) * 2.0 / (eventState->getXmax()-eventState->getXmin()) - 1.0; y = (y - eventState->getYmin())* 2.0 / (eventState->getYmax()-eventState->getYmin()) - 1.0; if (view_invert_y) y = - y; for(int i=getNumSlaves()-1; i>=0; --i) { const Slave& slave = getSlave(i); if (slave._camera.valid() && slave._camera->getAllowEventFocus() && slave._camera->getRenderTargetImplementation()==osg::Camera::FRAME_BUFFER) { OSG_INFO<<"Testing slave camera "<getName()<getViewport() : 0; osg::Matrix localCameraVPW = camera->getViewMatrix() * camera->getProjectionMatrix(); if (viewport) localCameraVPW *= viewport->computeWindowMatrix(); osg::Matrix matrix( osg::Matrix::inverse(masterCameraVPW) * localCameraVPW ); osg::Vec3d new_coord = osg::Vec3d(x,y,0.0) * matrix; //OSG_NOTICE<<" x="<getXmin()="<getXmin()<<" eventState->getXmax()="<getXmax()<= (viewport->x()-epsilon) && new_coord.y() >= (viewport->y()-epsilon) && new_coord.x() < (viewport->x()+viewport->width()-1.0+epsilon) && new_coord.y() <= (viewport->y()+viewport->height()-1.0+epsilon) ) { // OSG_NOTICE<<" in viewport "<x()<<" "<<(viewport->x()+viewport->width())<setGraphicsContext(gc); camera->setViewport(new osg::Viewport(0,0,width, height)); camera->setDrawBuffer(GL_FRONT); camera->setReadBuffer(GL_FRONT); camera->setAllowEventFocus(false); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture); addSlave(camera.get(), osg::Matrixd(), osg::Matrixd()); return camera.release(); } osg::Camera* View::assignKeystoneDistortionCamera(osg::DisplaySettings* ds, osg::GraphicsContext* gc, int x, int y, int width, int height, GLenum buffer, osg::Texture* texture, Keystone* keystone) { double screenDistance = ds->getScreenDistance(); double screenWidth = ds->getScreenWidth(); double screenHeight = ds->getScreenHeight(); double fovy = osg::RadiansToDegrees(2.0*atan2(screenHeight/2.0,screenDistance)); double aspectRatio = screenWidth/screenHeight; osg::Geode* geode = keystone->createKeystoneDistortionMesh(); // new we need to add the texture to the mesh, we do so by creating a // StateSet to contain the Texture StateAttribute. osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::TexMat* texmat = new osg::TexMat; texmat->setScaleByTextureRectangleSize(true); stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) ); camera->setViewport(new osg::Viewport(x, y, width, height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); camera->setViewMatrix(osg::Matrix::identity()); camera->setProjectionMatrixAsPerspective(fovy, aspectRatio, 0.1, 1000.0); // add subgraph to render camera->addChild(geode); camera->addChild(keystone->createGrid()); camera->setName("DistortionCorrectionCamera"); // camera->addEventCallback(new KeystoneHandler(keystone)); addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false); return camera.release(); } void View::StereoSlaveCallback::updateSlave(osg::View& view, osg::View::Slave& slave) { osg::Camera* camera = slave._camera.get(); osgViewer::View* viewer_view = dynamic_cast(&view); if (_ds.valid() && camera && viewer_view) { // inherit any settings applied to the master Camera. camera->inheritCullSettings(*(view.getCamera()), camera->getInheritanceMask()); if (_eyeScale<0.0) { camera->setCullMask(camera->getCullMaskLeft()); } else { camera->setCullMask(camera->getCullMaskRight()); } // set projection matrix if (_eyeScale<0.0) { camera->setProjectionMatrix(_ds->computeLeftEyeProjectionImplementation(view.getCamera()->getProjectionMatrix())); } else { camera->setProjectionMatrix(_ds->computeRightEyeProjectionImplementation(view.getCamera()->getProjectionMatrix())); } double sd = _ds->getScreenDistance(); double fusionDistance = sd; switch(viewer_view->getFusionDistanceMode()) { case(osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE): fusionDistance = viewer_view->getFusionDistanceValue(); break; case(osgUtil::SceneView::PROPORTIONAL_TO_SCREEN_DISTANCE): fusionDistance *= viewer_view->getFusionDistanceValue(); break; } double eyeScale = osg::absolute(_eyeScale) * (fusionDistance/sd); if (_eyeScale<0.0) { camera->setViewMatrix(_ds->computeLeftEyeViewImplementation(view.getCamera()->getViewMatrix(), eyeScale)); } else { camera->setViewMatrix(_ds->computeRightEyeViewImplementation(view.getCamera()->getViewMatrix(), eyeScale)); } } else { slave.updateSlaveImplementation(view); } } osg::Camera* View::assignStereoCamera(osg::DisplaySettings* ds, osg::GraphicsContext* gc, int x, int y, int width, int height, GLenum buffer, double eyeScale) { osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc); camera->setViewport(new osg::Viewport(x,y, width, height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); // add this slave camera to the viewer, with a shift left of the projection matrix addSlave(camera.get(), osg::Matrixd::identity(), osg::Matrixd::identity()); // assign update callback to maintain the correct view and projection matrices osg::View::Slave& slave = getSlave(getNumSlaves()-1); slave._updateSlaveCallback = new StereoSlaveCallback(ds, eyeScale); return camera.release(); } static const GLubyte patternVertEven[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; static const GLubyte patternHorzEven[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; // 32 x 32 bit array every row is a horizontal line of pixels // and the (bitwise) columns a vertical line // The following is a checkerboard pattern static const GLubyte patternCheckerboard[] = { 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA}; void View::assignStereoOrKeystoneToCamera(osg::Camera* camera, osg::DisplaySettings* ds) { if (!camera || camera->getGraphicsContext()==0) return; if (!ds->getStereo() && !ds->getKeystoneHint()) return; ds->setUseSceneViewForStereoHint(false); typedef std::vector< osg::ref_ptr > Keystones; Keystones keystones; if (ds->getKeystoneHint() && !ds->getKeystones().empty()) { for(osg::DisplaySettings::Objects::iterator itr = ds->getKeystones().begin(); itr != ds->getKeystones().end(); ++itr) { Keystone* keystone = dynamic_cast(itr->get()); if (keystone) keystones.push_back(keystone); } } if (ds->getKeystoneHint()) { while(keystones.size()<2) keystones.push_back(new Keystone); } // set up view's main camera { double height = ds->getScreenHeight(); double width = ds->getScreenWidth(); double distance = ds->getScreenDistance(); double vfov = osg::RadiansToDegrees(atan2(height/2.0f,distance)*2.0); camera->setProjectionMatrixAsPerspective( vfov, width/height, 1.0f,10000.0f); } osg::ref_ptr gc = camera->getGraphicsContext(); osg::ref_ptr traits = const_cast(camera->getGraphicsContext()->getTraits()); if (!ds->getStereo()) { // load or create a Keystone object osg::ref_ptr keystone = 0; if (!(ds->getKeystones().empty())) keystone = dynamic_cast(ds->getKeystones().front().get()); if (!keystone) keystone = new osgViewer::Keystone; // create distortion texture osg::ref_ptr texture = createDistortionTexture(traits->width, traits->height); // create RTT Camera assignRenderToTextureCamera(gc.get(), traits->width, traits->height, texture.get()); // create Keystone distortion camera osg::ref_ptr distortion_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, texture.get(), keystone.get()); // attach Keystone editing event handler. distortion_camera->addEventCallback(new KeystoneHandler(keystone.get())); camera->setGraphicsContext(0); return; } switch(ds->getStereoMode()) { case(osg::DisplaySettings::QUAD_BUFFER): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); // left Camera left buffer osg::ref_ptr left_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK_LEFT : GL_FRONT_LEFT, -1.0); left_camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); // right Camera right buffer osg::ref_ptr right_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK_RIGHT : GL_FRONT_RIGHT, 1.0); right_camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); // for keystone: // left camera to render to left texture // right camera to render to right texture // left keystone camera to render to left buffer // left keystone camera to render to right buffer // one keystone and editing for the one window if (!keystones.empty()) { // for keystone: // left camera to render to left texture using whole viewport of left texture // right camera to render to right texture using whole viewport of right texture // left keystone camera to render to left viewport/window // right keystone camera to render to right viewport/window // two keystone, one for each of the left and right viewports/windows osg::ref_ptr keystone = keystones.front(); // create distortion texture osg::ref_ptr left_texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera left_camera->setViewport(0, 0, traits->width, traits->height); left_camera->setDrawBuffer(GL_FRONT); left_camera->setReadBuffer(GL_FRONT); left_camera->setAllowEventFocus(true); left_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. left_camera->attach(osg::Camera::COLOR_BUFFER, left_texture.get()); // create distortion texture osg::ref_ptr right_texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera right_camera->setViewport(0, 0, traits->width, traits->height); right_camera->setDrawBuffer(GL_FRONT); right_camera->setReadBuffer(GL_FRONT); right_camera->setAllowEventFocus(true); right_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. right_camera->attach(osg::Camera::COLOR_BUFFER, right_texture.get()); // create Keystone left distortion camera keystone->setGridColor(osg::Vec4(1.0f,0.0f,0.0,1.0)); osg::ref_ptr left_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK_LEFT : GL_FRONT_LEFT, left_texture.get(), keystone.get()); left_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); // attach Keystone editing event handler. left_keystone_camera->addEventCallback(new KeystoneHandler(keystone.get())); // create Keystone right distortion camera osg::ref_ptr right_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK_RIGHT : GL_FRONT_RIGHT, right_texture.get(), keystone.get()); right_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 3); right_keystone_camera->setAllowEventFocus(false); } break; } case(osg::DisplaySettings::ANAGLYPHIC): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); // left Camera red osg::ref_ptr left_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0); left_camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); left_camera->getOrCreateStateSet()->setAttribute(new osg::ColorMask(true, false, false, true)); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); // right Camera cyan osg::ref_ptr right_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0); right_camera->setClearMask(GL_DEPTH_BUFFER_BIT); right_camera->getOrCreateStateSet()->setAttribute(new osg::ColorMask(false, true, true, true)); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); if (!keystones.empty()) { // for keystone: // left camera to render to texture using red colour mask // right camera to render to same texture using cyan colour mask // keystone camera to render to whole screen without colour masks // one keystone and editing for the one window osg::ref_ptr keystone = keystones.front(); bool useTwoTexture = true; if (useTwoTexture) { // create left distortion texture osg::ref_ptr left_texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera left_camera->setDrawBuffer(GL_FRONT); left_camera->setReadBuffer(GL_FRONT); left_camera->setAllowEventFocus(false); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); left_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); left_camera->getOrCreateStateSet()->removeAttribute(osg::StateAttribute::COLORMASK); left_camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // attach the texture and use it as the color buffer. left_camera->attach(osg::Camera::COLOR_BUFFER, left_texture.get()); // create left distortion texture osg::ref_ptr right_texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera right_camera->setDrawBuffer(GL_FRONT); right_camera->setReadBuffer(GL_FRONT); right_camera->setAllowEventFocus(false); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); right_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); right_camera->getOrCreateStateSet()->removeAttribute(osg::StateAttribute::COLORMASK); right_camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // attach the texture and use it as the color buffer. right_camera->attach(osg::Camera::COLOR_BUFFER, right_texture.get()); // create Keystone left distortion camera osg::ref_ptr left_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, left_texture.get(), keystone.get()); left_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); left_keystone_camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); left_keystone_camera->getOrCreateStateSet()->setAttribute(new osg::ColorMask(true, false, false, true)); // create Keystone right distortion camera osg::ref_ptr right_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, right_texture.get(), keystone.get()); right_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 3); right_keystone_camera->setClearMask(GL_DEPTH_BUFFER_BIT); right_keystone_camera->getOrCreateStateSet()->setAttribute(new osg::ColorMask(false, true, true, true)); // attach Keystone editing event handler. left_keystone_camera->addEventCallback(new KeystoneHandler(keystone.get())); camera->setAllowEventFocus(false); } else { // create distortion texture osg::ref_ptr texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera left_camera->setDrawBuffer(GL_FRONT); left_camera->setReadBuffer(GL_FRONT); left_camera->setAllowEventFocus(false); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); left_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. left_camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); // convert to RTT Camera right_camera->setDrawBuffer(GL_FRONT); right_camera->setReadBuffer(GL_FRONT); right_camera->setAllowEventFocus(false); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); right_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. right_camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); // create Keystone distortion camera osg::ref_ptr distortion_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, texture.get(), keystone.get()); distortion_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); // attach Keystone editing event handler. distortion_camera->addEventCallback(new KeystoneHandler(keystone.get())); camera->setAllowEventFocus(false); } } break; } case(osg::DisplaySettings::HORIZONTAL_SPLIT): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); bool left_eye_left_viewport = ds->getSplitStereoHorizontalEyeMapping()==osg::DisplaySettings::LEFT_EYE_LEFT_VIEWPORT; int left_start = (left_eye_left_viewport) ? 0 : traits->width/2; int right_start = (left_eye_left_viewport) ? traits->width/2 : 0; // left viewport Camera osg::ref_ptr left_camera = assignStereoCamera(ds, gc.get(), left_start, 0, traits->width/2, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0); // right viewport Camera osg::ref_ptr right_camera = assignStereoCamera(ds, gc.get(), right_start, 0, traits->width/2, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0); if (!keystones.empty()) { // for keystone: // left camera to render to left texture using whole viewport of left texture // right camera to render to right texture using whole viewport of right texture // left keystone camera to render to left viewport/window // right keystone camera to render to right viewport/window // two keystone, one for each of the left and right viewports/windows osg::ref_ptr left_keystone = keystones[0]; osg::ref_ptr right_keystone = keystones[1]; // create distortion texture osg::ref_ptr left_texture = createDistortionTexture(traits->width/2, traits->height); // convert to RTT Camera left_camera->setViewport(0, 0, traits->width/2, traits->height); left_camera->setDrawBuffer(GL_FRONT); left_camera->setReadBuffer(GL_FRONT); left_camera->setAllowEventFocus(true); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); left_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. left_camera->attach(osg::Camera::COLOR_BUFFER, left_texture.get()); // create distortion texture osg::ref_ptr right_texture = createDistortionTexture(traits->width/2, traits->height); // convert to RTT Camera right_camera->setViewport(0, 0, traits->width/2, traits->height); right_camera->setDrawBuffer(GL_FRONT); right_camera->setReadBuffer(GL_FRONT); right_camera->setAllowEventFocus(true); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); right_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. right_camera->attach(osg::Camera::COLOR_BUFFER, right_texture.get()); // create Keystone left distortion camera left_keystone->setGridColor(osg::Vec4(1.0f,0.0f,0.0,1.0)); osg::ref_ptr left_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), left_start, 0, traits->width/2, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, left_texture.get(), left_keystone.get()); left_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); // attach Keystone editing event handler. left_keystone_camera->addEventCallback(new KeystoneHandler(left_keystone.get())); // create Keystone right distortion camera right_keystone->setGridColor(osg::Vec4(0.0f,1.0f,0.0,1.0)); osg::ref_ptr right_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), right_start, 0, traits->width/2, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, right_texture.get(), right_keystone.get()); right_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 3); // attach Keystone editing event handler. right_keystone_camera->addEventCallback(new KeystoneHandler(right_keystone.get())); camera->setAllowEventFocus(false); } break; } case(osg::DisplaySettings::VERTICAL_SPLIT): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); bool left_eye_bottom_viewport = ds->getSplitStereoVerticalEyeMapping()==osg::DisplaySettings::LEFT_EYE_BOTTOM_VIEWPORT; int left_start = (left_eye_bottom_viewport) ? 0 : traits->height/2; int right_start = (left_eye_bottom_viewport) ? traits->height/2 : 0; // bottom viewport Camera osg::ref_ptr left_camera = assignStereoCamera(ds, gc.get(), 0, left_start, traits->width, traits->height/2, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0); // top vieport camera osg::ref_ptr right_camera = assignStereoCamera(ds, gc.get(), 0, right_start, traits->width, traits->height/2, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0); // for keystone: // left camera to render to left texture using whole viewport of left texture // right camera to render to right texture using whole viewport of right texture // left keystone camera to render to left viewport/window // right keystone camera to render to right viewport/window // two keystone, one for each of the left and right viewports/windows if (!keystones.empty()) { // for keystone: // left camera to render to left texture using whole viewport of left texture // right camera to render to right texture using whole viewport of right texture // left keystone camera to render to left viewport/window // right keystone camera to render to right viewport/window // two keystone, one for each of the left and right viewports/windows osg::ref_ptr left_keystone = keystones[0]; osg::ref_ptr right_keystone = keystones[1]; // create distortion texture osg::ref_ptr left_texture = createDistortionTexture(traits->width, traits->height/2); // convert to RTT Camera left_camera->setViewport(0, 0, traits->width, traits->height/2); left_camera->setDrawBuffer(GL_FRONT); left_camera->setReadBuffer(GL_FRONT); left_camera->setAllowEventFocus(true); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); left_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. left_camera->attach(osg::Camera::COLOR_BUFFER, left_texture.get()); // create distortion texture osg::ref_ptr right_texture = createDistortionTexture(traits->width, traits->height/2); // convert to RTT Camera right_camera->setViewport(0, 0, traits->width, traits->height/2); right_camera->setDrawBuffer(GL_FRONT); right_camera->setReadBuffer(GL_FRONT); right_camera->setAllowEventFocus(true); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); right_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. right_camera->attach(osg::Camera::COLOR_BUFFER, right_texture.get()); // create Keystone left distortion camera left_keystone->setGridColor(osg::Vec4(1.0f,0.0f,0.0,1.0)); osg::ref_ptr left_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, left_start, traits->width, traits->height/2, traits->doubleBuffer ? GL_BACK : GL_FRONT, left_texture.get(), left_keystone.get()); left_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); // attach Keystone editing event handler. left_keystone_camera->addEventCallback(new KeystoneHandler(left_keystone.get())); // create Keystone right distortion camera right_keystone->setGridColor(osg::Vec4(0.0f,1.0f,0.0,1.0)); osg::ref_ptr right_keystone_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, right_start, traits->width, traits->height/2, traits->doubleBuffer ? GL_BACK : GL_FRONT, right_texture.get(), right_keystone.get()); right_keystone_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 3); // attach Keystone editing event handler. right_keystone_camera->addEventCallback(new KeystoneHandler(right_keystone.get())); camera->setAllowEventFocus(false); } break; } case(osg::DisplaySettings::LEFT_EYE): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); // single window, whole window, just left eye offsets osg::ref_ptr left_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0); // for keystone: // treat as standard keystone correction. // left eye camera to render to texture // keystone camera then render to window // one keystone and editing for window if (!keystones.empty()) { // for keystone: // left camera to render to texture using red colour mask // right camera to render to same texture using cyan colour mask // keystone camera to render to whole screen without colour masks // one keystone and editing for the one window osg::ref_ptr keystone = keystones.front(); // create distortion texture osg::ref_ptr texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera left_camera->setDrawBuffer(GL_FRONT); left_camera->setReadBuffer(GL_FRONT); left_camera->setAllowEventFocus(false); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); left_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. left_camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); // create Keystone distortion camera osg::ref_ptr distortion_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, texture.get(), keystone.get()); distortion_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); // attach Keystone editing event handler. distortion_camera->addEventCallback(new KeystoneHandler(keystone.get())); } break; } case(osg::DisplaySettings::RIGHT_EYE): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); // single window, whole window, just right eye offsets osg::ref_ptr right_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0); // for keystone: // treat as standard keystone correction. // left eye camera to render to texture // keystone camera then render to window // one keystone and editing for window if (!keystones.empty()) { // for keystone: // left camera to render to texture using red colour mask // right camera to render to same texture using cyan colour mask // keystone camera to render to whole screen without colour masks // one keystone and editing for the one window osg::ref_ptr keystone = keystones.front(); // create distortion texture osg::ref_ptr texture = createDistortionTexture(traits->width, traits->height); // convert to RTT Camera right_camera->setDrawBuffer(GL_FRONT); right_camera->setReadBuffer(GL_FRONT); right_camera->setAllowEventFocus(false); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); right_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // attach the texture and use it as the color buffer. right_camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); // create Keystone distortion camera osg::ref_ptr distortion_camera = assignKeystoneDistortionCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, texture.get(), keystone.get()); distortion_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); // attach Keystone editing event handler. distortion_camera->addEventCallback(new KeystoneHandler(keystone.get())); } break; } case(osg::DisplaySettings::HORIZONTAL_INTERLACE): case(osg::DisplaySettings::VERTICAL_INTERLACE): case(osg::DisplaySettings::CHECKERBOARD): { // disconect the camera from the graphics context. camera->setGraphicsContext(0); // set up the stencil buffer { osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setViewport(0, 0, traits->width, traits->height); camera->setDrawBuffer(traits->doubleBuffer ? GL_BACK : GL_FRONT); camera->setReadBuffer(camera->getDrawBuffer()); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); camera->setClearStencil(0); camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0); addSlave(camera.get(), false); osg::ref_ptr geometry = osg::createTexturedQuadGeometry(osg::Vec3(-1.0f,-1.0f,0.0f), osg::Vec3(2.0f,0.0f,0.0f), osg::Vec3(0.0f,2.0f,0.0f), 0.0f, 0.0f, 1.0f, 1.0f); osg::ref_ptr geode = new osg::Geode; geode->addDrawable(geometry.get()); camera->addChild(geode.get()); geode->setCullingActive(false); osg::ref_ptr stateset = geode->getOrCreateStateSet(); // set up stencil osg::ref_ptr stencil = new osg::Stencil; stencil->setFunction(osg::Stencil::ALWAYS, 1, ~0u); stencil->setOperation(osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE); stencil->setWriteMask(~0u); stateset->setAttributeAndModes(stencil.get(), osg::StateAttribute::ON); // set up polygon stipple if(ds->getStereoMode() == osg::DisplaySettings::VERTICAL_INTERLACE) { stateset->setAttributeAndModes(new osg::PolygonStipple(patternVertEven), osg::StateAttribute::ON); } else if(ds->getStereoMode() == osg::DisplaySettings::HORIZONTAL_INTERLACE) { stateset->setAttributeAndModes(new osg::PolygonStipple(patternHorzEven), osg::StateAttribute::ON); } else { stateset->setAttributeAndModes(new osg::PolygonStipple(patternCheckerboard), osg::StateAttribute::ON); } stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); } // left Camera { osg::ref_ptr left_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0); left_camera->setClearMask(0); left_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); left_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1); osg::ref_ptr stencil = new osg::Stencil; stencil->setFunction(osg::Stencil::EQUAL, 0, ~0u); stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP); left_camera->getOrCreateStateSet()->setAttributeAndModes(stencil.get(), osg::StateAttribute::ON); } // right Camera { osg::ref_ptr right_camera = assignStereoCamera(ds, gc.get(), 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0); right_camera->setClearMask(GL_DEPTH_BUFFER_BIT); right_camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2); osg::ref_ptr stencil = new osg::Stencil; stencil->setFunction(osg::Stencil::NOTEQUAL, 0, ~0u); stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP); right_camera->getOrCreateStateSet()->setAttributeAndModes(stencil.get(), osg::StateAttribute::ON); } break; } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/IOSUtils.mm0000644000175000017500000002234013151044751023632 0ustar albertoalberto/* * DarwinUtils.cpp * OpenSceneGraph * * Created by Stephan Huber on 27.06.08. * Copyright 2008 Stephan Maximilian Huber, digital mind. All rights reserved. * */ #include #include #include #import #include "IOSUtils.h" namespace osgIOS { class AutoReleasePoolHelper { public: AutoReleasePoolHelper() { pool = [[NSAutoreleasePool alloc] init]; } ~AutoReleasePoolHelper() { [pool release]; } private: NSAutoreleasePool* pool; }; /** ctor, get a list of all attached displays */ IOSWindowingSystemInterface::IOSWindowingSystemInterface() : osg::GraphicsContext::WindowingSystemInterface() { } /** dtor */ IOSWindowingSystemInterface::~IOSWindowingSystemInterface() { if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } } /** @return count of attached screens */ unsigned int IOSWindowingSystemInterface::getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si) { AutoReleasePoolHelper auto_release_pool_helper; return [[UIScreen screens] count]; } void IOSWindowingSystemInterface::getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution) { AutoReleasePoolHelper auto_release_pool_helper; if(si.screenNum >= [[UIScreen screens] count]){return;} //get the screens array from the UIScreen class NSArray* screens = [UIScreen screens]; //iterate to the desired screen num UIScreen* screen = [screens objectAtIndex:si.screenNum]; if (si.screenNum == 0) { //internal display supports only one mode, UiScreenMode reports wrong sizes for internal display at least for iOS 3.2 float scale = 1.0f; #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) scale = [screen scale]; #endif resolution.width = [screen bounds].size.width * scale; resolution.height = [screen bounds].size.height * scale; resolution.colorDepth = 24; resolution.refreshRate = 60; //i've read 60 is max, not sure if thats true } else { //get the screen mode NSArray* modesArray = [screen availableModes]; if(modesArray) { //for this method we copy the first mode (default) then return UIScreenMode* mode = [modesArray objectAtIndex:0]; CGSize size = [mode size]; resolution.width = size.width; resolution.height = size.height; resolution.colorDepth = 24; resolution.refreshRate = 60; //i've read 60 is max, not sure if thats true OSG_INFO << "new resolution for screen " << si.screenNum << ": " << size.width << "x" << size.height << std::endl; } } } // //Due to the weird void IOSWindowingSystemInterface::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList) { AutoReleasePoolHelper auto_release_pool_helper; if(si.screenNum >= [[UIScreen screens] count]){return;} //get the screens array from the UIScreen class NSArray* screens = [UIScreen screens]; //get the desired screen num UIScreen* screen = [screens objectAtIndex:si.screenNum]; if (si.screenNum == 0) { //internal display supports only one mode, UiScreenMode reports wrong sizes for internal screen at least for iOS 3.2 osg::GraphicsContext::ScreenSettings resolution; float scale = 1.0f; #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) scale = [screen scale]; #endif resolution.width = [screen bounds].size.width * scale; resolution.height = [screen bounds].size.height * scale; resolution.colorDepth = 24; resolution.refreshRate = 60; //i've read 60 is max, not sure if thats true resolutionList.push_back(resolution); } else { // external display may support more resolutions: //get the screen mode NSArray* modesArray = [screen availableModes]; NSEnumerator* modesEnum = [modesArray objectEnumerator]; UIScreenMode* mode; //iterate over modes and get their size property while ( mode = [modesEnum nextObject] ) { osg::GraphicsContext::ScreenSettings resolution; CGSize size = [mode size]; resolution.width = size.width; resolution.height = size.height; resolution.colorDepth = 24; resolution.refreshRate = 60; //i've read 60 is max, not sure if thats true resolutionList.push_back(resolution); OSG_INFO << "new resolution: " << size.width << "x" << size.height << std::endl; } } } bool IOSWindowingSystemInterface::setScreenSettings(const osg::GraphicsContext::ScreenIdentifier &si, const osg::GraphicsContext::ScreenSettings & settings) { bool result = setScreenResolutionImpl(si, settings.width, settings.height); if (result) setScreenRefreshRateImpl(si, settings.refreshRate); return result; } /** implementation of setScreenResolution */ //IPad can have extenal screens which we can request a res for //the main screen screenNum 0 can not currently have its res changed //as it only has one mode (might change though and this should still handle it) // bool IOSWindowingSystemInterface::setScreenResolutionImpl(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height) { AutoReleasePoolHelper auto_release_pool_helper; if(si.screenNum >= [[UIScreen screens] count]){return false;} //get the screens array from the UIScreen class NSArray* screens = [UIScreen screens]; //iterate to the desired screen num UIScreen* screen = [screens objectAtIndex:si.screenNum]; //get the screen mode NSArray* modesArray = [screen availableModes]; NSEnumerator* modesEnum = [modesArray objectEnumerator]; UIScreenMode* mode; //iterate over modes and get their size property while ( mode = [modesEnum nextObject] ) { osg::GraphicsContext::ScreenSettings resolution; CGSize size = [mode size]; //if the modes size/resolution matches the passed width/height then assign this //mode as the screens current mode if(size.width == width && size.height == height) { screen.currentMode = mode; OSG_INFO << "IOSWindowingSystemInterface::setScreenResolutionImpl: Set resolution of screen '" << si.screenNum << "', to '" << width << ", " << height << "'." << std::endl; return true; } } OSG_WARN << "IOSWindowingSystemInterface::setScreenResolutionImpl: Failed to set resolution of screen '" << si.screenNum << "', to '" << width << ", " << height << "'." << std::endl; return false; } /** implementation of setScreenRefreshRate, don't think you can do this on IOS */ bool IOSWindowingSystemInterface::setScreenRefreshRateImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) { return true; } unsigned int IOSWindowingSystemInterface::getScreenContaining(int x, int y, int w, int h) { return 1; } // //return the UIScreen object asscoiated with the passed ScreenIdentifier //returns nil if si isn't found // UIScreen* IOSWindowingSystemInterface::getUIScreen(const osg::GraphicsContext::ScreenIdentifier& si) { AutoReleasePoolHelper auto_release_pool_helper; if(si.screenNum >= [[UIScreen screens] count]){return nil;} UIScreen* screen = [[UIScreen screens] objectAtIndex:si.screenNum]; return screen; } // //Returns the contents scale factor of the screen, this is the scale factor required //to convert points to pixels on this screen // bool IOSWindowingSystemInterface::getScreenContentScaleFactor(const osg::GraphicsContext::ScreenIdentifier& si, float& scaleFactor) { AutoReleasePoolHelper auto_release_pool_helper; if(si.screenNum >= [[UIScreen screens] count]){return false;} UIScreen* screen = this->getUIScreen(si); if(screen != nil) { scaleFactor = 1.0f; #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) CGFloat scale = [screen scale]; scaleFactor = scale; #endif return true; } return false; } // //Returns the screens size in points, docs state a point is roughly 1/160th of an inch // bool IOSWindowingSystemInterface::getScreenSizeInPoints(const osg::GraphicsContext::ScreenIdentifier& si, osg::Vec2& pointSize) { AutoReleasePoolHelper auto_release_pool_helper; if(si.screenNum >= [[UIScreen screens] count]){return false;} UIScreen* screen = this->getUIScreen(si); if(screen != nil) { CGRect bounds = [screen bounds]; pointSize.x() = bounds.size.width; pointSize.y() = bounds.size.height; return true; } return false; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/0000755000175000017500000000000013151044751023070 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/AcrossAllScreens.cpp0000644000175000017500000001166713151044751027015 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include using namespace osgViewer; void AcrossAllScreens::configure(osgViewer::View& view) const { osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (!wsi) { OSG_NOTICE<<"AcrossAllScreens::configure() : Error, no WindowSystemInterface available, cannot create windows."<getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar); osg::GraphicsContext::ScreenIdentifier si; si.readDISPLAY(); // displayNum has not been set so reset it to 0. if (si.displayNum<0) si.displayNum = 0; unsigned int numScreens = wsi->getNumScreens(si); if (numScreens==1) { osg::ref_ptr ss = new SingleScreen(0); ss->configure(view); } else { double translate_x = 0.0; for(unsigned int i=0; igetScreenResolution(si, width, height); translate_x += double(width) / (double(height) * aspectRatio); } bool stereoSplitScreens = numScreens==2 && ds->getStereoMode()==osg::DisplaySettings::HORIZONTAL_SPLIT && ds->getStereo(); for(unsigned int i=0; igetScreenResolution(si, width, height); osg::ref_ptr traits = new osg::GraphicsContext::Traits(ds); traits->hostName = si.hostName; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->screenNum = i; traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); osgViewer::GraphicsWindow* gw = dynamic_cast(gc.get()); if (gw) { OSG_INFO<<" GraphicsWindow has been created successfully."<getEventQueue()->getCurrentEventState()->setWindowRectangle(traits->x, traits->y, traits->width, traits->height ); } else { OSG_NOTICE<<" GraphicsWindow has not been created successfully."<setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); if (stereoSplitScreens) { unsigned int leftCameraNum = (ds->getSplitStereoHorizontalEyeMapping()==osg::DisplaySettings::LEFT_EYE_LEFT_VIEWPORT) ? 0 : 1; osg::ref_ptr ds_local = new osg::DisplaySettings(*ds); ds_local->setStereoMode(leftCameraNum==i ? osg::DisplaySettings::LEFT_EYE : osg::DisplaySettings::RIGHT_EYE); camera->setDisplaySettings(ds_local.get()); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd() ); } else { double newAspectRatio = double(traits->width) / double(traits->height); double aspectRatioChange = newAspectRatio / aspectRatio; view.addSlave(camera.get(), osg::Matrixd::translate( translate_x - aspectRatioChange, 0.0, 0.0) * osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0), osg::Matrixd() ); translate_x -= aspectRatioChange * 2.0; } } } view.assignSceneDataToCameras(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/WoWVxDisplay.cpp0000644000175000017500000003451613151044751026165 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; void WoWVxDisplay::configure(osgViewer::View& view) const { OSG_INFO<<"WoWVxDisplay::configure(...)"<getScreenResolution(si, width, height); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->hostName = si.hostName; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); if (!gc) { OSG_NOTICE<<"GraphicsWindow has not been created successfully."<setTextureSize(tex_width, tex_height); texture->setInternalFormat(GL_RGB); texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); osg::Texture2D* textureD = new osg::Texture2D; textureD->setTextureSize(tex_width, tex_height); textureD->setInternalFormat(GL_DEPTH_COMPONENT); textureD->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); textureD->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); #if 0 osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::SEPERATE_WINDOW; GLenum buffer = GL_FRONT; #else osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT; GLenum buffer = GL_FRONT; #endif // front face { osg::ref_ptr camera = new osg::Camera; camera->setName("Front face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture); camera->attach(osg::Camera::DEPTH_BUFFER, textureD); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd()); } // WoW display set up. { osg::Texture1D *textureHeader = new osg::Texture1D(); // Set up the header { unsigned char header[]= {0xF1,_wow_content,_wow_factor,_wow_offset,0x00,0x00,0x00,0x00,0x00,0x00}; // Calc the CRC32 { unsigned long _register = 0; for(int i = 0; i < 10; ++i) { unsigned char mask = 0x80; unsigned char byte = header[i]; for (int j = 0; j < 8; ++j) { bool topBit = (_register & 0x80000000) != 0; _register <<= 1; _register ^= ((byte & mask) != 0? 0x1: 0x0); if (topBit) { _register ^= 0x04c11db7; } mask >>= 1; } } unsigned char *p = (unsigned char*) &_register; for(size_t i = 0; i < 4; ++i) { header[i+6] = p[3-i]; } } osg::ref_ptr imageheader = new osg::Image(); imageheader->allocateImage(256,1,1,GL_LUMINANCE,GL_UNSIGNED_BYTE); { unsigned char *cheader = imageheader->data(); for (int x=0; x<256; ++x){ cheader[x] = 0; } for (int x=0; x<=9; ++x){ for (int y=7; y>=0; --y){ int i = 2*(7-y)+16*x; cheader[i] = (((1<<(y))&(header[x])) << (7-(y))); } } } textureHeader->setImage(imageheader.get()); } // Create the Screen Aligned Quad osg::Geode* geode = new osg::Geode(); { osg::Geometry* geom = new osg::Geometry; osg::Vec3Array* vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0,height,0)); vertices->push_back(osg::Vec3(0,0,0)); vertices->push_back(osg::Vec3(width,0,0)); vertices->push_back(osg::Vec3(width,height,0)); geom->setVertexArray(vertices); osg::Vec2Array* tex = new osg::Vec2Array; tex->push_back(osg::Vec2(0,1)); tex->push_back(osg::Vec2(0,0)); tex->push_back(osg::Vec2(1,0)); tex->push_back(osg::Vec2(1,1)); geom->setTexCoordArray(0,tex); geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4)); geode->addDrawable(geom); // new we need to add the textures to the quad, and setting up the shader. osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, textureHeader,osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(1, texture,osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(2, textureD,osg::StateAttribute::ON); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::ref_ptr programShader = new osg::Program(); stateset->setAttribute(programShader.get(), osg::StateAttribute::ON); stateset->addUniform( new osg::Uniform("wow_width", (int)width)); stateset->addUniform( new osg::Uniform("wow_height", (int)height)); stateset->addUniform( new osg::Uniform("wow_disparity_M", _wow_disparity_M)); stateset->addUniform( new osg::Uniform("wow_disparity_Zd", _wow_disparity_Zd)); stateset->addUniform( new osg::Uniform("wow_disparity_vz", _wow_disparity_vz)); stateset->addUniform( new osg::Uniform("wow_disparity_C", _wow_disparity_C)); stateset->addUniform(new osg::Uniform("wow_header", 0)); stateset->addUniform(new osg::Uniform("wow_tcolor", 1)); stateset->addUniform(new osg::Uniform("wow_tdepth", 2)); osg::Shader *frag = new osg::Shader(osg::Shader::FRAGMENT); frag->setShaderSource(" "\ " uniform sampler1D wow_header; " \ " uniform sampler2D wow_tcolor; " \ " uniform sampler2D wow_tdepth; " \ " " \ " uniform int wow_width; " \ " uniform int wow_height; " \ " uniform float wow_disparity_M; " \ " uniform float wow_disparity_Zd; " \ " uniform float wow_disparity_vz; " \ " uniform float wow_disparity_C; " \ " " \ " float disparity(float Z) " \ " { " \ " return (wow_disparity_M*(1.0-(wow_disparity_vz/(Z-wow_disparity_Zd+wow_disparity_vz))) " \ " + wow_disparity_C) / 255.0; " \ " } " \ " " \ " void main() " \ " { " \ " vec2 pos = (gl_FragCoord.xy / vec2(wow_width/2,wow_height) ); " \ " if (gl_FragCoord.x > float(wow_width/2)) " \ " { " \ " gl_FragColor = vec4(disparity(( texture2D(wow_tdepth, pos - vec2(1,0))).z)); " \ " } " \ " else{ " \ " gl_FragColor = texture2D(wow_tcolor, pos); " \ " } " \ " if ( (gl_FragCoord.y >= float(wow_height-1)) && (gl_FragCoord.x < 256.0) ) " \ " { " \ " float pos = gl_FragCoord.x/256.0; " \ " float blue = texture1D(wow_header, pos).b; " \ " if ( blue < 0.5) " \ " gl_FragColor.b = 0.0; " \ " else " \ " gl_FragColor.b = 1.0; " \ " } " \ " } " ); programShader->addShader(frag); } // Create the Camera { osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) ); camera->setViewport(new osg::Viewport(0, 0, width, height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setAllowEventFocus(false); camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); camera->setProjectionMatrixAsOrtho2D(0,width,0,height); camera->setViewMatrix(osg::Matrix::identity()); // add subgraph to render camera->addChild(geode); camera->setName("WoWCamera"); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false); } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/SingleScreen.cpp0000644000175000017500000000211313151044751026152 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include using namespace osgViewer; void SingleScreen::configure(osgViewer::View& view) const { osg::ref_ptr singleWindow = new SingleWindow(0,0,-1,-1,_screenNum); singleWindow->setWindowDecoration(false); singleWindow->configure(view); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/PanoramicSphericalDisplay.cpp0000644000175000017500000002516313151044751030675 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; osg::Geometry* PanoramicSphericalDisplay::createParoramicSphericalDisplayDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, double sphere_radius, double collar_radius, osg::Image* intensityMap, const osg::Matrix& projectorMatrix) const { osg::Vec3d center(0.0,0.0,0.0); osg::Vec3d eye(0.0,0.0,0.0); double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius); bool flip = false; bool texcoord_flip = false; osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance); OSG_INFO<<"createParoramicSphericalDisplayDistortionMesh : Projector position = "<getScreenResolution(si, width, height); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->hostName = si.hostName; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; bool applyIntensityMapAsColours = true; osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); if (!gc) { OSG_NOTICE<<"GraphicsWindow has not been created successfully."<setTextureSize(tex_width, tex_height); texture->setInternalFormat(GL_RGB); texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); #if 0 osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::SEPERATE_WINDOW; GLenum buffer = GL_FRONT; #else osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT; GLenum buffer = GL_FRONT; #endif // front face { osg::ref_ptr camera = new osg::Camera; camera->setName("Front face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd()); } // distortion correction set up. { osg::Geode* geode = new osg::Geode(); geode->addDrawable(createParoramicSphericalDisplayDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), _radius, _collar, applyIntensityMapAsColours ? _intensityMap.get() : 0, _projectorMatrix)); // new we need to add the texture to the mesh, we do so by creating a // StateSet to contain the Texture StateAttribute. osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::TexMat* texmat = new osg::TexMat; texmat->setScaleByTextureRectangleSize(true); stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); if (!applyIntensityMapAsColours && _intensityMap.valid()) { stateset->setTextureAttributeAndModes(1, new osg::Texture2D(_intensityMap.get()), osg::StateAttribute::ON); } osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) ); camera->setViewport(new osg::Viewport(0, 0, width, height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setAllowEventFocus(false); camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); camera->setProjectionMatrixAsOrtho2D(0,width,0,height); camera->setViewMatrix(osg::Matrix::identity()); // add subgraph to render camera->addChild(geode); camera->setName("DistortionCorrectionCamera"); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/SphericalDisplay.cpp0000644000175000017500000003731013151044751027040 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; osg::Geometry* SphericalDisplay::create3DSphericalDisplayDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, double sphere_radius, double collar_radius,osg::Image* intensityMap, const osg::Matrix& projectorMatrix) const { osg::Vec3d center(0.0,0.0,0.0); osg::Vec3d eye(0.0,0.0,0.0); double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius); bool centerProjection = false; osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance); OSG_INFO<<"create3DSphericalDisplayDistortionMesh : Projector position = "<getScreenResolution(si, width, height); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->hostName = si.hostName; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); if (!gc) { OSG_NOTICE<<"GraphicsWindow has not been created successfully."<setTextureSize(tex_width, tex_height); texture->setInternalFormat(GL_RGB); texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_EDGE); #if 0 osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::SEPERATE_WINDOW; GLenum buffer = GL_FRONT; #else osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT; GLenum buffer = GL_FRONT; #endif // front face { osg::ref_ptr camera = new osg::Camera; camera->setName("Front face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, osg::TextureCubeMap::POSITIVE_Y); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd()); } // top face { osg::ref_ptr camera = new osg::Camera; camera->setName("Top face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, osg::TextureCubeMap::POSITIVE_Z); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::rotate(osg::inDegrees(-90.0f), 1.0,0.0,0.0)); } // left face { osg::ref_ptr camera = new osg::Camera; camera->setName("Left face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, osg::TextureCubeMap::NEGATIVE_X); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::rotate(osg::inDegrees(-90.0f), 0.0,1.0,0.0) * osg::Matrixd::rotate(osg::inDegrees(-90.0f), 0.0,0.0,1.0)); } // right face { osg::ref_ptr camera = new osg::Camera; camera->setName("Right face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, osg::TextureCubeMap::POSITIVE_X); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::rotate(osg::inDegrees(90.0f), 0.0,1.0,0.0 ) * osg::Matrixd::rotate(osg::inDegrees(90.0f), 0.0,0.0,1.0)); } // bottom face { osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setName("Bottom face camera"); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, osg::TextureCubeMap::NEGATIVE_Z); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::rotate(osg::inDegrees(90.0f), 1.0,0.0,0.0) * osg::Matrixd::rotate(osg::inDegrees(180.0f), 0.0,0.0,1.0)); } // back face { osg::ref_ptr camera = new osg::Camera; camera->setName("Back face camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, osg::TextureCubeMap::NEGATIVE_Y); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::rotate(osg::inDegrees(180.0f), 1.0,0.0,0.0)); } view.getCamera()->setProjectionMatrixAsPerspective(90.0f, 1.0, 1, 1000.0); // distortion correction set up. { osg::Geode* geode = new osg::Geode(); geode->addDrawable(create3DSphericalDisplayDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), _radius, _collar, applyIntensityMapAsColours ? _intensityMap.get() : 0, _projectorMatrix)); // new we need to add the texture to the mesh, we do so by creating a // StateSet to contain the Texture StateAttribute. osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); if (!applyIntensityMapAsColours && _intensityMap.valid()) { stateset->setTextureAttributeAndModes(1, new osg::Texture2D(_intensityMap.get()), osg::StateAttribute::ON); } osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) ); camera->setViewport(new osg::Viewport(0, 0, width, height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setAllowEventFocus(true); camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); camera->setProjectionMatrixAsOrtho2D(0,width,0,height); camera->setViewMatrix(osg::Matrix::identity()); // add subgraph to render camera->addChild(geode); camera->setName("DistortionCorrectionCamera"); view.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false); } view.getCamera()->setNearFarRatio(0.0001f); if (view.getLightingMode()==osg::View::HEADLIGHT) { // set a local light source for headlight to ensure that lighting is consistent across sides of cube. view.getLight()->setPosition(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/config/SingleWindow.cpp0000644000175000017500000001006713151044751026211 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; void SingleWindow::configure(osgViewer::View& view) const { osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (!wsi) { OSG_NOTICE<<"SingleWindow::configure() : Error, no WindowSystemInterface available, cannot create windows."< traits = new osg::GraphicsContext::Traits(ds); traits->readDISPLAY(); if (traits->displayNum<0) traits->displayNum = 0; traits->screenNum = _screenNum; traits->x = _x; traits->y = _y; traits->width = _width; traits->height = _height; traits->windowDecoration = _windowDecoration; traits->overrideRedirect = _overrideRedirect; traits->doubleBuffer = true; traits->sharedContext = 0; if (traits->width<=0 || traits->height<=0 ) { osg::GraphicsContext::ScreenIdentifier si; si.readDISPLAY(); // displayNum has not been set so reset it to 0. if (si.displayNum<0) si.displayNum = 0; si.screenNum = _screenNum; unsigned int width, height; wsi->getScreenResolution(si, width, height); if (traits->width<=0) traits->width = width; if (traits->height<=0) traits->height = height; } osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); view.getCamera()->setGraphicsContext(gc.get()); osgViewer::GraphicsWindow* gw = dynamic_cast(gc.get()); if (gw) { OSG_INFO<<"View::setUpViewOnSingleScreen - GraphicsWindow has been created successfully."<getEventQueue()->getCurrentEventState()->setWindowRectangle(traits->x, traits->y, traits->width, traits->height ); } else { OSG_NOTICE<<" GraphicsWindow has not been created successfully."<getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar); double newAspectRatio = double(traits->width) / double(traits->height); double aspectRatioChange = newAspectRatio / aspectRatio; if (aspectRatioChange != 1.0) { view.getCamera()->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); } view.getCamera()->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; view.getCamera()->setDrawBuffer(buffer); view.getCamera()->setReadBuffer(buffer); if (ds->getKeystoneHint()) { if (ds->getKeystoneHint() && !ds->getKeystoneFileNames().empty()) { osgViewer::Keystone::loadKeystoneFiles(ds); } if (ds->getKeystones().empty()) ds->getKeystones().push_back(new Keystone); view.assignStereoOrKeystoneToCamera(view.getCamera(), ds); } else if (ds->getStereo() && ds->getUseSceneViewForStereoHint()) { view.assignStereoOrKeystoneToCamera(view.getCamera(), ds); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/GraphicsWindowIOS.mm0000644000175000017500000012222613151044751025466 0ustar albertoalberto #include #include #import #import #if OSG_GLES1_FEATURES #import #else #import #if OSG_GLES3_FEATURES #import #endif // in GLES2, the OES suffix if dropped from function names (from rti) #define glGenFramebuffersOES glGenFramebuffers #define glGenRenderbuffersOES glGenRenderbuffers #define glBindFramebufferOES glBindFramebuffer #define glBindRenderbufferOES glBindRenderbuffer #define glFramebufferRenderbufferOES glFramebufferRenderbuffer #define glGetRenderbufferParameterivOES glGetRenderbufferParameteriv #define glRenderbufferStorageOES glRenderbufferStorage #define glDeleteRenderbuffersOES glDeleteRenderbuffers #define glDeleteFramebuffersOES glDeleteFramebuffers #define glCheckFramebufferStatusOES glCheckFramebufferStatus #define GL_FRAMEBUFFER_OES GL_FRAMEBUFFER #define GL_RENDERBUFFER_OES GL_RENDERBUFFER #define GL_RENDERBUFFER_WIDTH_OES GL_RENDERBUFFER_WIDTH #define GL_RENDERBUFFER_HEIGHT_OES GL_RENDERBUFFER_HEIGHT #define GL_COLOR_ATTACHMENT0_OES GL_COLOR_ATTACHMENT0 #define GL_DEPTH_ATTACHMENT_OES GL_DEPTH_ATTACHMENT #define GL_DEPTH_COMPONENT16_OES GL_DEPTH_COMPONENT16 #define GL_STENCIL_INDEX8_OES GL_STENCIL_INDEX8 #define GL_FRAMEBUFFER_COMPLETE_OES GL_FRAMEBUFFER_COMPLETE #define GL_STENCIL_ATTACHMENT_OES GL_STENCIL_ATTACHMENT #define GL_RGB5_A1_OES GL_RGB5_A1 #endif #include "IOSUtils.h" #pragma mark GraphicsWindowIOSWindow // ---------------------------------------------------------------------------------------------------------- // GraphicsWindowIOSWindow, implements canBecomeKeyWindow + canBecomeMainWindow // ---------------------------------------------------------------------------------------------------------- @interface GraphicsWindowIOSWindow : UIWindow { } - (BOOL) canBecomeKeyWindow; - (BOOL) canBecomeMainWindow; @end @implementation GraphicsWindowIOSWindow // //Implement dealloc // - (void) dealloc { [super dealloc]; } - (BOOL) canBecomeKeyWindow { return YES; } - (BOOL) canBecomeMainWindow { return YES; } @end #pragma mark GraphicsWindowIOSGLView // ---------------------------------------------------------------------------------------------------------- // GraphicsWindowIOSGLView // custom UIView-class handling creation and display of frame/render buffers plus receives touch input // ---------------------------------------------------------------------------------------------------------- typedef std::map TouchPointsIdMapping; @interface GraphicsWindowIOSGLView : UIView { @private osgViewer::GraphicsWindowIOS* _win; EAGLContext* _context; /* The pixel dimensions of the backbuffer */ GLint _backingWidth; GLint _backingHeight; //the pixel buffers for the video /* OpenGL names for the renderbuffer and framebuffers used to render to this view */ GLuint _viewRenderbuffer, _viewFramebuffer; /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ GLuint _depthRenderbuffer; /* OpenGL name for the stencil buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ GLuint _stencilBuffer; // for multisampled antialiased rendering GLuint _msaaFramebuffer, _msaaRenderBuffer, _msaaDepthBuffer; TouchPointsIdMapping* _touchPointsIdMapping; unsigned int _lastTouchPointId; } - (void)setGraphicsWindow: (osgViewer::GraphicsWindowIOS*) win; - (osgViewer::GraphicsWindowIOS*) getGraphicsWindow; - (void)setOpenGLContext: (EAGLContext*) context; - (void)updateDimensions; - (BOOL)createFramebuffer; - (void)destroyFramebuffer; - (void)swapBuffers; - (void)bindFrameBuffer; - (BOOL)acceptsFirstResponder; - (BOOL)becomeFirstResponder; - (BOOL)resignFirstResponder; - (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (UITouchPhase) phase; - (osg::Vec2) convertPointToPixel: (osg::Vec2) point; - (void) dealloc; @end @implementation GraphicsWindowIOSGLView - (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (UITouchPhase) phase { switch(phase) { case UITouchPhaseBegan: return osgGA::GUIEventAdapter::TOUCH_BEGAN; break; case UITouchPhaseMoved: return osgGA::GUIEventAdapter::TOUCH_MOVED; break; case UITouchPhaseStationary: return osgGA::GUIEventAdapter::TOUCH_STATIONERY; break; case UITouchPhaseEnded: case UITouchPhaseCancelled: return osgGA::GUIEventAdapter::TOUCH_ENDED; break; } return osgGA::GUIEventAdapter::TOUCH_ENDED; } - (unsigned int)computeTouchId: (UITouch*) touch mayCleanup: (bool)may_cleanup { unsigned int result(0); if (!_touchPointsIdMapping) { _lastTouchPointId = 0; _touchPointsIdMapping = new TouchPointsIdMapping(); } switch([touch phase]) { case UITouchPhaseBegan: { TouchPointsIdMapping::iterator itr = _touchPointsIdMapping->find(touch); // std::cout << "new: " << touch << " num: " << _touchPointsIdMapping->size() << " found: " << (itr != _touchPointsIdMapping->end()) << std::endl; if (itr == _touchPointsIdMapping->end()) { (*_touchPointsIdMapping)[touch] = result = _lastTouchPointId; _lastTouchPointId++; break; } } // missing "break" by intention! case UITouchPhaseMoved: case UITouchPhaseStationary: { result = (*_touchPointsIdMapping)[touch]; } break; case UITouchPhaseEnded: case UITouchPhaseCancelled: { TouchPointsIdMapping::iterator itr = _touchPointsIdMapping->find(touch); // std::cout<< "remove: " << touch << " num: " << _touchPointsIdMapping->size() << " found: " << (itr != _touchPointsIdMapping->end()) << std::endl; if (itr != _touchPointsIdMapping->end()) { result = itr->second; if(may_cleanup) _touchPointsIdMapping->erase(itr); } if(_touchPointsIdMapping->size() == 0) { _lastTouchPointId = 0; } // std::cout<< "remove: " << touch << " num: " << _touchPointsIdMapping->size() << std::endl; } break; default: break; } return result; } - (osg::Vec2) convertPointToPixel: (osg::Vec2) point { //get the views contentscale factor and multiply the point by it float scale = 1.0f; #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) scale = self.contentScaleFactor; #endif return osg::Vec2(point.x()*scale, point.y()*scale); } -(void) setGraphicsWindow: (osgViewer::GraphicsWindowIOS*) win { _win = win; _touchPointsIdMapping = new TouchPointsIdMapping(); _lastTouchPointId = 0; } - (osgViewer::GraphicsWindowIOS*) getGraphicsWindow { return _win; } -(void) setOpenGLContext: (EAGLContext*) context { _context = context; } // You must implement this method + (Class)layerClass { return [CAEAGLLayer class]; } // //Called when the view is created using a frame for dimensions // - (id)initWithFrame:(CGRect)frame : (osgViewer::GraphicsWindowIOS*)win{ _win = win; if ((self = [super initWithFrame:frame])) { // Get the layer CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; osgViewer::GraphicsWindowIOS::WindowData* win_data(NULL); if (_win->getTraits()->inheritedWindowData.valid()) win_data = dynamic_cast(_win->getTraits()->inheritedWindowData.get()); eaglLayer.opaque = win_data ? !win_data->getCreateTransparentView() : YES; bool retained_backing = win_data ? win_data->getUseRetainedBacking() : NO; if(_win->getTraits()->alpha > 0) { //create layer with alpha channel RGBA8 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:retained_backing], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; }else{ //else no alpha, IOS uses RBG565 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:retained_backing], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil]; } } self.multipleTouchEnabled = YES; return self; } // //Implement dealloc to destory our frame buffer // - (void) dealloc { OSG_INFO << "GraphicsWindowIOSGLView::dealloc" << std::endl; if(_touchPointsIdMapping) delete _touchPointsIdMapping; _touchPointsIdMapping = NULL; [super dealloc]; } - (void)layoutSubviews { [super layoutSubviews]; [self updateDimensions]; } - (void) setFrame:(CGRect)frame { [super setFrame:frame]; [self updateDimensions]; } - (void) updateDimensions { if (_win) { CGRect frame = self.bounds; osg::Vec2 pointOrigin = osg::Vec2(frame.origin.x,frame.origin.y); osg::Vec2 pointSize = osg::Vec2(frame.size.width,frame.size.height); osg::Vec2 pixelOrigin = [(GraphicsWindowIOSGLView*)(self) convertPointToPixel:pointOrigin]; osg::Vec2 pixelSize = [(GraphicsWindowIOSGLView*)(self) convertPointToPixel:pointSize]; OSG_INFO << "updateDimensions, resize to " << pixelOrigin.x() << " " << pixelOrigin.y() << " " << pixelSize.x() << " " << pixelSize.y() << std::endl; _win->resized(pixelOrigin.x(), pixelOrigin.y(), pixelSize.x(), pixelSize.y()); } } - (BOOL)createFramebuffer { _msaaFramebuffer = _msaaRenderBuffer = 0; glGenFramebuffersOES(1, &_viewFramebuffer); glGenRenderbuffersOES(1, &_viewRenderbuffer); // set the default id for osg to switch back after using fbos. _win->setDefaultFboId(_viewFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_backingHeight); osg::notify(osg::DEBUG_INFO) << "GraphicsWindowIOS::createFramebuffer INFO: Created GL RenderBuffer of size " << _backingWidth << ", " << _backingHeight << " ." << std::endl; #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 //on ios 5 we have to use a packed depth stencil buffer if we want stencil if(_win->getTraits()->depth > 0) { //add stencil if requested if(_win->getTraits()->stencil > 0) { // Create a packed depth stencil buffer. glGenRenderbuffersOES(1, &_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); }else{ //normal depth buffer glGenRenderbuffersOES(1, &_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthRenderbuffer); if(_win->getTraits()->depth == 16) { glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, _backingWidth, _backingHeight); }else if(_win->getTraits()->depth == 24){ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); } glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); } } #else //add depth if requested if(_win->getTraits()->depth > 0) { glGenRenderbuffersOES(1, &_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthRenderbuffer); if(_win->getTraits()->depth == 16) { glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, _backingWidth, _backingHeight); }else if(_win->getTraits()->depth == 24){ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); } #if defined(GL_DEPTH_COMPONENT32_OES) else if(_win->getTraits()->depth == 32){ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT32_OES, _backingWidth, _backingHeight); } #endif glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); } //add stencil if requested if(_win->getTraits()->stencil > 0) { glGenRenderbuffersOES(1, &_stencilBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _stencilBuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, _backingWidth, _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _stencilBuffer); } #endif //MSAA only available for >= 4.0 sdk #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if(_win->getTraits()->sampleBuffers > 0) { glGenFramebuffersOES(1, &_msaaFramebuffer); glGenRenderbuffersOES(1, &_msaaRenderBuffer); _win->setDefaultFboId(_msaaFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, _msaaFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _msaaRenderBuffer); // Samples is the amount of pixels the MSAA buffer uses to make one pixel on the render // buffer. Use a small number like 2 for the 3G and below and 4 or more for newer models // NOTE: Formats of draw and read buffers must be identical GLenum internalFormat = GL_RGB5_A1_OES; # if OSG_GLES3_FEATURES if ([_context API] == kEAGLRenderingAPIOpenGLES3) internalFormat = GL_RGBA8_OES; # endif glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, _win->getTraits()->samples, internalFormat, _backingWidth, _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _msaaRenderBuffer); glGenRenderbuffersOES(1, &_msaaDepthBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _msaaDepthBuffer); GLuint attachmentType = (_win->getTraits()->stencil > 0) ? GL_DEPTH24_STENCIL8_OES : ((_win->getTraits()->depth == 16) ? GL_DEPTH_COMPONENT16_OES : GL_DEPTH_COMPONENT24_OES); glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, _win->getTraits()->samples, attachmentType, _backingWidth , _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _msaaDepthBuffer); if (_win->getTraits()->stencil > 0) { glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _msaaDepthBuffer); } } #endif if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { OSG_FATAL << "GraphicsWindowIOS::createFramebuffer ERROR: Failed to create a GL RenderBuffer, glCheckFramebufferStatusOES returned '" << glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) << "'." << std::endl; return NO; } return YES; } - (void)destroyFramebuffer { if(_viewFramebuffer) { glDeleteFramebuffersOES(1, &_viewFramebuffer); _viewFramebuffer = 0; } if(_viewRenderbuffer) { glDeleteRenderbuffersOES(1, &_viewRenderbuffer); _viewRenderbuffer = 0; } if(_depthRenderbuffer) { glDeleteRenderbuffersOES(1, &_depthRenderbuffer); _depthRenderbuffer = 0; } if(_stencilBuffer) { glDeleteRenderbuffersOES(1, &_stencilBuffer); _stencilBuffer = 0; } if(_msaaRenderBuffer) { glDeleteRenderbuffersOES(1, &_msaaRenderBuffer); _msaaRenderBuffer = 0; } if(_msaaDepthBuffer) { glDeleteRenderbuffersOES(1, &_msaaDepthBuffer); _msaaDepthBuffer = 0; } if(_msaaFramebuffer) { glDeleteFramebuffersOES(1, &_msaaFramebuffer); _msaaFramebuffer = 0; } } // //Swap the view and render buffers // - (void)swapBuffers { #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if (_msaaFramebuffer) { // Resolve the contents from the multisampling buffer into the resolve (view) buffer glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, _msaaFramebuffer); glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, _viewFramebuffer); # if OSG_GLES3_FEATURES if ([_context API] == kEAGLRenderingAPIOpenGLES3) { glBlitFramebuffer(0, 0, _backingWidth, _backingHeight, 0, 0, _backingWidth, _backingHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); } else glResolveMultisampleFramebufferAPPLE(); # else glResolveMultisampleFramebufferAPPLE(); # endif } #endif // Present Results step glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if (_msaaFramebuffer) { // Invalidate (discard) step (must be after present step) GLenum attachments[] = {GL_DEPTH_ATTACHMENT_OES, GL_COLOR_ATTACHMENT0_OES}; # if OSG_GLES3_FEATURES if ([_context API] == kEAGLRenderingAPIOpenGLES3) glInvalidateFramebuffer(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); else glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); # else glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); # endif } #endif [self bindFrameBuffer]; } // //bind view buffer as current for new render pass // - (void)bindFrameBuffer { #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if (_msaaFramebuffer) { # if OSG_GLES3_FEATURES if ([_context API] == kEAGLRenderingAPIOpenGLES3) { glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, _msaaFramebuffer); glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, _viewFramebuffer); } else glBindFramebufferOES(GL_FRAMEBUFFER_OES, _msaaFramebuffer); # else glBindFramebufferOES(GL_FRAMEBUFFER_OES, _msaaFramebuffer); # endif } else glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); #else glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); #endif } - (BOOL)acceptsFirstResponder { return YES; } - (BOOL)becomeFirstResponder { return YES; } - (BOOL)resignFirstResponder { return YES; } // //Touch input callbacks // - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouches]; osg::ref_ptr osg_event(NULL); for(int i=0; i<[allTouches count]; i++) { UITouch *touch = [[allTouches allObjects] objectAtIndex:i]; CGPoint pos = [touch locationInView:self]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); } } [super touchesBegan:touches withEvent:event]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouches]; osg::ref_ptr osg_event(NULL); for(int i=0; i<[allTouches count]; i++) { UITouch *touch = [[allTouches allObjects] objectAtIndex:i]; CGPoint pos = [touch locationInView:self]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); } } [super touchesMoved:touches withEvent:event]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouches]; osg::ref_ptr osg_event(NULL); for(int i=0; i<[allTouches count]; i++) { UITouch *touch = [[allTouches allObjects] objectAtIndex:i]; CGPoint pos = [touch locationInView:self]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]); } } [super touchesEnded:touches withEvent:event]; } -(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesEnded: touches withEvent:event]; } @end @interface GraphicsWindowIOSGLViewController : UIViewController { } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration; @end @implementation GraphicsWindowIOSGLViewController - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { osgViewer::GraphicsWindowIOS* win = [(GraphicsWindowIOSGLView*)(self.view) getGraphicsWindow]; if(!win){return NO;} osgViewer::GraphicsWindowIOS::WindowData::DeviceOrientationFlags flags = win->getDeviceOrientationFlags(); BOOL result(NO); switch (interfaceOrientation) { case UIDeviceOrientationPortrait: if(flags & osgViewer::GraphicsWindowIOS::WindowData::PORTRAIT_ORIENTATION){ result = YES; } break; case UIDeviceOrientationPortraitUpsideDown: if(flags & osgViewer::GraphicsWindowIOS::WindowData::PORTRAIT_UPSIDEDOWN_ORIENTATION){ result = YES; } break; case UIInterfaceOrientationLandscapeLeft: if(win->getTraits()->supportsResize && flags & osgViewer::GraphicsWindowIOS::WindowData::LANDSCAPE_LEFT_ORIENTATION){ result = YES; } break; case UIInterfaceOrientationLandscapeRight: if(win->getTraits()->supportsResize && flags & osgViewer::GraphicsWindowIOS::WindowData::LANDSCAPE_RIGHT_ORIENTATION){ result = YES; } break; default: break; } OSG_INFO << "shouldAutorotateToInterfaceOrientation for " << interfaceOrientation << ": " << ((result==YES) ? "YES" : "NO") << std::endl; return result; } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { [(GraphicsWindowIOSGLView*)(self.view) updateDimensions]; } @end using namespace osgIOS; namespace osgViewer { #pragma mark GraphicsWindowIOS // ---------------------------------------------------------------------------------------------------------- // init // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::init() { if (_initialized) return; _ownsWindow = false; _context = NULL; _window = NULL; _view = NULL; _viewController = NULL; _updateContext = true; //if -1.0 we use the screens scale factor _viewContentScaleFactor = -1.0f; _valid = _initialized = true; // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); } // ---------------------------------------------------------------------------------------------------------- // realizeImplementation, creates the window + context // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::realizeImplementation() { if (_realized) return true; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; BOOL bar_hidden = (_traits->windowDecoration) ? NO: YES; #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED #if __IPHONE_OS_VERSION_MIN_REQUIRED > 30100 [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden withAnimation:UIStatusBarAnimationNone]; #else [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden animated:NO]; #endif #endif //Get info about the requested screen IOSWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); osg::Vec2 screenSizePoints; osg::Vec2 screenSizePixels; float screenScaleFactor = 1.0f; UIScreen* screen = nil; osg::GraphicsContext::ScreenSettings screenSettings; if (wsi) { wsi->getScreenContentScaleFactor((*_traits), screenScaleFactor); wsi->getScreenSizeInPoints((*_traits), screenSizePoints); screenSizePixels = osg::Vec2(screenSettings.width, screenSettings.height); wsi->getScreenSettings((*_traits), screenSettings); screen = wsi->getUIScreen((*_traits)); }else{ OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create IOS windowing system, OSG will be unable to create a vaild gl context and will not be able to render." << std::endl; return false; } _ownsWindow = true; // see if an existing inherited window was passed in WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast(_traits->inheritedWindowData.get()) : NULL; if (windowData) { if (windowData->getWindowOrParentView()) { _ownsWindow = false; _window = windowData->getWindowOrParentView(); } _deviceOrientationFlags = windowData->_deviceOrientationFlags; _viewContentScaleFactor = windowData->_viewContentScaleFactor; } //if the user hasn't specified a viewScaleFactor we will use the screens scale factor //so we get a full res buffer if(_viewContentScaleFactor < 0.0f) {_viewContentScaleFactor = screenScaleFactor;} OSG_DEBUG << "GraphicsWindowIOS::realizeImplementation / ownsWindow: " << _ownsWindow << std::endl; //Here's the confusing bit, the default traits use the screen res which is in pixels and the user will want to use pixels also //but we need to create our views and windows in points. By default we create a full res buffer across all devices. This //means that for backward compatibility you need to set the windowData _viewContentScaleFactor to 1.0f and set the screen res to the //res of the older gen device. CGRect window_bounds; osg::Vec2 pointsOrigin = this->pixelToPoint(osg::Vec2(_traits->x, _traits->y)); osg::Vec2 pointsSize = this->pixelToPoint(osg::Vec2(_traits->width, _traits->height)); window_bounds.origin.x = pointsOrigin.x(); window_bounds.origin.y = pointsOrigin.y(); window_bounds.size.width = pointsSize.x(); window_bounds.size.height = pointsSize.y(); //if we own the window we need to create one if (_ownsWindow) { //create the IOS window object using the viewbounds (in points) required for our context size _window = [[GraphicsWindowIOSWindow alloc] initWithFrame: window_bounds];// styleMask: style backing: NSBackingStoreBuffered defer: NO]; if (!_window) { OSG_WARN << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create GraphicsWindowIOSWindow can not display gl view" << std::endl; return false; } OSG_DEBUG << "GraphicsWindowIOS::realizeImplementation: INFO: Created UIWindow with bounds '" << window_bounds.size.width << ", " << window_bounds.size.height << "' (points)." << std::endl; //if the user has requested a differnet screenNum from default 0 get the UIScreen object and //apply to our window (this is for IPad external screens, I don't have one, so I've no idea if it works) //I'm also not sure if we should apply this to external windows also? if(_traits->screenNum > 0 && screen != nil) { _window.screen = screen; } } //create the desired OpenGLES context type #if OSG_GLES1_FEATURES _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; #elif OSG_GLES2_FEATURES #if OSG_GLES3_FEATURES _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; #endif if (!_context) _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; #endif if (!_context || ![EAGLContext setCurrentContext:_context]) { #if OSG_GLES1_FEATURES OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create a valid OpenGLES1 context" << std::endl; #elif OSG_GLES2_FEATURES #if OSG_GLES3_FEATURES OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create a valid OpenGLES3 or OpenGLES2 context" << std::endl; #else OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create a valid OpenGLES2 context" << std::endl; #endif #endif return false; } //create the view to display our context in our window CGRect gl_view_bounds = (_ownsWindow) ? [_window frame] : window_bounds; GraphicsWindowIOSGLView* theView = [[ GraphicsWindowIOSGLView alloc ] initWithFrame: gl_view_bounds : this ]; if(!theView) { OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create GraphicsWindowIOSGLView, can not create frame buffers." << std::endl; return false; } [theView setAutoresizingMask: ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight) ]; //Apply our content scale factor to our view, this is what converts the views points //size to our desired context size. #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) theView.contentScaleFactor = _viewContentScaleFactor; #endif [theView setGraphicsWindow: this]; [theView setOpenGLContext:_context]; _view = theView; OSG_DEBUG << "GraphicsWindowIOS::realizeImplementation / view: " << theView << std::endl; if (getDeviceOrientationFlags() != WindowData::IGNORE_ORIENTATION) { _viewController = [[GraphicsWindowIOSGLViewController alloc] init]; _viewController.view = _view; } // Attach view to window [_window addSubview: _view]; if ([_window isKindOfClass:[UIWindow class]]) _window.rootViewController = _viewController; [theView release]; //if we own the window also make it visible if (_ownsWindow) { //show window [_window makeKeyAndVisible]; } [pool release]; // IOSs origin is top/left: getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); _valid = _initialized = _realized = true; return _valid; } // ---------------------------------------------------------------------------------------------------------- // closeImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::closeImplementation() { OSG_INFO << "close IOS window" << std::endl; _valid = false; _realized = false; if (_view) { [_view setOpenGLContext: NULL]; [_context release]; [_view removeFromSuperview]; [_view setGraphicsWindow: NULL]; } if (_viewController) { [_viewController release]; _viewController = NULL; } if (_window && _ownsWindow) { [_window release]; //[glView release]; } _window = NULL; _view = NULL; _context = NULL; } // ---------------------------------------------------------------------------------------------------------- // makeCurrentImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS:: makeCurrentImplementation() { //bind the context [EAGLContext setCurrentContext:_context]; if (_updateContext) { [_view destroyFramebuffer]; [_view createFramebuffer]; _updateContext = false; } //i think we also want to bind the frame buffer here // [_view bindFrameBuffer]; return true; } // ---------------------------------------------------------------------------------------------------------- // releaseContextImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::releaseContextImplementation() { if ([EAGLContext currentContext] == _context) { [EAGLContext setCurrentContext:nil]; } return true; } // ---------------------------------------------------------------------------------------------------------- // swapBuffersImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::swapBuffersImplementation() { //[_context flushBuffer]; [_view swapBuffers]; } // ---------------------------------------------------------------------------------------------------------- // setWindowDecorationImplementation // // We will use this to toggle the status bar on IPhone, nearest thing to window decoration // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::setWindowDecorationImplementation(bool flag) { if (!_realized || !_ownsWindow) return false; BOOL bar_hidden = (flag) ? NO: YES; #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED #if __IPHONE_OS_VERSION_MIN_REQUIRED > 30100 [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden withAnimation:UIStatusBarAnimationNone]; #else [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden animated:NO]; #endif #endif return true; } // ---------------------------------------------------------------------------------------------------------- // grabFocus // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::grabFocus() { //i think make key is the equivalent of focus on iphone [_window makeKeyWindow]; } // ---------------------------------------------------------------------------------------------------------- // grabFocusIfPointerInWindow // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::grabFocusIfPointerInWindow() { OSG_INFO << "GraphicsWindowIOS :: grabFocusIfPointerInWindow not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // raiseWindow // Raise the window to the top. // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::raiseWindow() { [_window bringSubviewToFront:_view]; } // ---------------------------------------------------------------------------------------------------------- // resizedImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::resizedImplementation(int x, int y, int width, int height) { GraphicsContext::resizedImplementation(x, y, width, height); _updateContext = true; getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime()); } // ---------------------------------------------------------------------------------------------------------- // setWindowRectangleImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::setWindowRectangleImplementation(int x, int y, int width, int height) { OSG_INFO << "GraphicsWindowIOS :: setWindowRectangleImplementation not implemented yet " << std::endl; if (!_ownsWindow) return false; return true; } bool GraphicsWindowIOS::checkEvents() { return !(getEventQueue()->empty()); } // ---------------------------------------------------------------------------------------------------------- // setWindowName // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::setWindowName (const std::string & name) { OSG_INFO << "GraphicsWindowIOS :: setWindowName not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // useCursor, no cursor on IOS // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::useCursor(bool cursorOn) { OSG_INFO << "GraphicsWindowIOS :: useCursor not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // setCursor, no cursor on IOS // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::setCursor(MouseCursor mouseCursor) { OSG_INFO << "GraphicsWindowIOS :: setCursor not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // setVSync, no vsync on IOS // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::setVSync(bool f) { OSG_INFO << "GraphicsWindowIOS :: setVSync not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // helper funcs for converting points to pixels taking into account the views contents scale factor // ---------------------------------------------------------------------------------------------------------- osg::Vec2 GraphicsWindowIOS::pointToPixel(const osg::Vec2& point) { return point * _viewContentScaleFactor; } osg::Vec2 GraphicsWindowIOS::pixelToPoint(const osg::Vec2& pixel) { float scaler = 1.0f / _viewContentScaleFactor; return pixel * scaler; } // ---------------------------------------------------------------------------------------------------------- // d'tor // ---------------------------------------------------------------------------------------------------------- GraphicsWindowIOS::~GraphicsWindowIOS() { close(); } class ConcreteIOSWindowingSystemInterface : public IOSWindowingSystemInterface { public: ConcreteIOSWindowingSystemInterface() : IOSWindowingSystemInterface() { } virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) { if (traits->pbuffer) { // pbuffers not supported on iOS return 0; } else { osg::ref_ptr window = new GraphicsWindowIOS(traits); if (window->valid()) return window.release(); else return 0; } } }; }//end namspace RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy; // declare C entry point for static compilation. extern "C" void graphicswindow_IOS(void) { osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::ConcreteIOSWindowingSystemInterface()); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/ViewerEventHandlers.cpp0000644000175000017500000007353313151044751026266 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace osgViewer { /* ** WindowSizeHandler */ WindowSizeHandler::WindowSizeHandler() : _keyEventToggleFullscreen('f'), _toggleFullscreen(true), _keyEventWindowedResolutionUp('>'), _keyEventWindowedResolutionDown('<'), _changeWindowedResolution(true), _currentResolutionIndex(-1) { _resolutionList.push_back(osg::Vec2(640, 480)); _resolutionList.push_back(osg::Vec2(800, 600)); _resolutionList.push_back(osg::Vec2(1024, 768)); _resolutionList.push_back(osg::Vec2(1152, 864)); _resolutionList.push_back(osg::Vec2(1280, 720)); _resolutionList.push_back(osg::Vec2(1280, 768)); _resolutionList.push_back(osg::Vec2(1280, 1024)); _resolutionList.push_back(osg::Vec2(1440, 900)); _resolutionList.push_back(osg::Vec2(1400, 1050)); _resolutionList.push_back(osg::Vec2(1600, 900)); _resolutionList.push_back(osg::Vec2(1600, 1024)); _resolutionList.push_back(osg::Vec2(1600, 1200)); _resolutionList.push_back(osg::Vec2(1680, 1050)); _resolutionList.push_back(osg::Vec2(1920, 1080)); _resolutionList.push_back(osg::Vec2(1920, 1200)); _resolutionList.push_back(osg::Vec2(2048, 1536)); _resolutionList.push_back(osg::Vec2(2560, 2048)); _resolutionList.push_back(osg::Vec2(3200, 2400)); _resolutionList.push_back(osg::Vec2(3840, 2400)); } void WindowSizeHandler::getUsage(osg::ApplicationUsage &usage) const { usage.addKeyboardMouseBinding(_keyEventToggleFullscreen, "Toggle full screen."); usage.addKeyboardMouseBinding(_keyEventWindowedResolutionUp, "Increase the screen resolution (in windowed mode)."); usage.addKeyboardMouseBinding(_keyEventWindowedResolutionDown, "Decrease the screen resolution (in windowed mode)."); } bool WindowSizeHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) { osgViewer::View* view = dynamic_cast(&aa); if (!view) return false; osgViewer::ViewerBase* viewer = view->getViewerBase(); if (viewer == NULL) { return false; } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): { if (_toggleFullscreen == true && ea.getKey() == _keyEventToggleFullscreen) { // sleep to allow any viewer rendering threads to complete before we // resize the window OpenThreads::Thread::microSleep(100000); osgViewer::Viewer::Windows windows; viewer->getWindows(windows); for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); itr != windows.end(); ++itr) { toggleFullscreen(*itr); } aa.requestRedraw(); return true; } else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionUp) { // sleep to allow any viewer rendering threads to complete before we // resize the window OpenThreads::Thread::microSleep(100000); // Increase resolution osgViewer::Viewer::Windows windows; viewer->getWindows(windows); for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); itr != windows.end(); ++itr) { changeWindowedResolution(*itr, true); } aa.requestRedraw(); return true; } else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionDown) { // sleep to allow any viewer rendering threads to complete before we // resize the window OpenThreads::Thread::microSleep(100000); // Decrease resolution osgViewer::Viewer::Windows windows; viewer->getWindows(windows); for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); itr != windows.end(); ++itr) { changeWindowedResolution(*itr, false); } aa.requestRedraw(); return true; } break; } default: break; } return false; } void WindowSizeHandler::toggleFullscreen(osgViewer::GraphicsWindow *window) { osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (wsi == NULL) { OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; return; } unsigned int screenWidth; unsigned int screenHeight; wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight); int x; int y; int width; int height; window->getWindowRectangle(x, y, width, height); bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight; if (isFullScreen) { osg::Vec2 resolution; if (_currentResolutionIndex == -1) { _currentResolutionIndex = getNearestResolution(screenWidth, screenHeight, screenWidth / 2, screenHeight / 2); } resolution = _resolutionList[_currentResolutionIndex]; window->setWindowDecoration(true); window->setWindowRectangle((screenWidth - (int)resolution.x()) / 2, (screenHeight - (int)resolution.y()) / 2, (int)resolution.x(), (int)resolution.y()); OSG_INFO << "Screen resolution = " << (int)resolution.x() << "x" << (int)resolution.y() << std::endl; } else { window->setWindowDecoration(false); window->setWindowRectangle(0, 0, screenWidth, screenHeight); } window->grabFocusIfPointerInWindow(); } void WindowSizeHandler::changeWindowedResolution(osgViewer::GraphicsWindow *window, bool increase) { osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (wsi == NULL) { OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; return; } unsigned int screenWidth; unsigned int screenHeight; wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight); int x; int y; int width; int height; window->getWindowRectangle(x, y, width, height); bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight; if (window->getWindowDecoration() == true || isFullScreen == false) { osg::Vec2 resolution; if (_currentResolutionIndex == -1) { _currentResolutionIndex = getNearestResolution(screenWidth, screenHeight, width, height); } if (increase == true) { // Find the next resolution for (int i = _currentResolutionIndex + 1; i < (int)_resolutionList.size(); ++i) { if ((unsigned int)_resolutionList[i].x() <= screenWidth && (unsigned int)_resolutionList[i].y() <= screenHeight) { _currentResolutionIndex = i; break; } } } else { // Find the previous resolution for (int i = _currentResolutionIndex - 1; i >= 0; --i) { if ((unsigned int)_resolutionList[i].x() <= screenWidth && (unsigned int)_resolutionList[i].y() <= screenHeight) { _currentResolutionIndex = i; break; } } } resolution = _resolutionList[_currentResolutionIndex]; window->setWindowDecoration(true); window->setWindowRectangle((screenWidth - (int)resolution.x()) / 2, (screenHeight - (int)resolution.y()) / 2, (int)resolution.x(), (int)resolution.y()); OSG_INFO << "Screen resolution = " << (int)resolution.x() << "x" << (int)resolution.y() << std::endl; window->grabFocusIfPointerInWindow(); } } unsigned int WindowSizeHandler::getNearestResolution(int screenWidth, int screenHeight, int width, int height) const { unsigned int position = 0; unsigned int result = 0; int delta = INT_MAX; for (std::vector::const_iterator it = _resolutionList.begin(); it != _resolutionList.end(); ++it, ++position) { if ((int)it->x() <= screenWidth && (int)it->y() <= screenHeight) { int tmp = static_cast(osg::absolute((width * height) - (it->x() * it->y()))); if (tmp < delta) { delta = tmp; result = position; } } } return (result); } /* ** ThreadingHandler */ ThreadingHandler::ThreadingHandler() : _keyEventChangeThreadingModel('m'), _changeThreadingModel(true), _keyEventChangeEndBarrierPosition('e'), _changeEndBarrierPosition(true) { _tickOrLastKeyPress = osg::Timer::instance()->tick(); } void ThreadingHandler::getUsage(osg::ApplicationUsage &usage) const { usage.addKeyboardMouseBinding(_keyEventChangeThreadingModel, "Toggle threading model."); usage.addKeyboardMouseBinding(_keyEventChangeEndBarrierPosition, "Toggle the placement of the end of frame barrier."); } bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) { osgViewer::View* view = dynamic_cast(&aa); if (!view) return false; osgViewer::ViewerBase* viewerBase = view->getViewerBase(); osgViewer::Viewer* viewer = dynamic_cast(viewerBase); if (viewerBase == NULL) { return false; } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): { double delta = osg::Timer::instance()->delta_s(_tickOrLastKeyPress, osg::Timer::instance()->tick()); if (_changeThreadingModel == true && ea.getKey() == _keyEventChangeThreadingModel && delta > 1.0) { _tickOrLastKeyPress = osg::Timer::instance()->tick(); switch(viewerBase->getThreadingModel()) { case(osgViewer::ViewerBase::SingleThreaded): viewerBase->setThreadingModel(osgViewer::ViewerBase::CullDrawThreadPerContext); OSG_NOTICE<<"Threading model 'CullDrawThreadPerContext' selected."<setThreadingModel(osgViewer::ViewerBase::DrawThreadPerContext); OSG_NOTICE<<"Threading model 'DrawThreadPerContext' selected."<setThreadingModel(osgViewer::ViewerBase::CullThreadPerCameraDrawThreadPerContext); OSG_NOTICE<<"Threading model 'CullThreadPerCameraDrawThreadPerContext' selected."<setThreadingModel(osgViewer::ViewerBase::SingleThreaded); OSG_NOTICE<<"Threading model 'SingleThreaded' selected."<setThreadingModel(osgViewer::ViewerBase::SingleThreaded); OSG_NOTICE<<"Threading model 'SingleThreaded' selected."<setThreadingModel(viewer->suggestBestThreadingModel()); OSG_NOTICE<<"Threading model 'AutomaticSelection' selected."<getEndBarrierPosition()) { case(osgViewer::Viewer::BeforeSwapBuffers): viewer->setEndBarrierPosition(osgViewer::Viewer::AfterSwapBuffers); OSG_NOTICE<<"Threading end of frame barrier position 'AfterSwapBuffers' selected."<setEndBarrierPosition(osgViewer::Viewer::BeforeSwapBuffers); OSG_NOTICE<<"Threading end of frame barrier position 'BeforeSwapBuffers' selected."<tick()) { const char* str = getenv("OSG_RECORD_CAMERA_PATH_FPS"); if (str) { _interval = 1.0f / osg::asciiToDouble(str); } else { _interval = 1.0f / fps; } } void RecordCameraPathHandler::getUsage(osg::ApplicationUsage &usage) const { usage.addKeyboardMouseBinding(_keyEventToggleRecord, "Toggle camera path recording."); usage.addKeyboardMouseBinding(_keyEventTogglePlayback, "Toggle camera path playback."); } bool RecordCameraPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) { osgViewer::View* view = dynamic_cast(&aa); if (view == NULL) { return false; } if(ea.getEventType()==osgGA::GUIEventAdapter::FRAME) { // Calculate our current delta (difference) in time between the last frame and // current frame, regardless of whether we actually store a ControlPoint... osg::Timer_t time = osg::Timer::instance()->tick(); double delta = osg::Timer::instance()->delta_s(_lastFrameTime, time); _lastFrameTime = time; // If our internal _delta is finally large enough to warrant a ControlPoint // insertion, do so now. Be sure and reset the internal _delta, so we can start // calculating when the next insert should happen. if (_animPath.valid() && _currentlyRecording && _delta >= _interval) { const osg::Matrixd& m = view->getCamera()->getInverseViewMatrix(); double animationPathTime = osg::Timer::instance()->delta_s(_animStartTime, time); _animPath->insert(animationPathTime, osg::AnimationPath::ControlPoint(m.getTrans(), m.getRotate())); _delta = 0.0f; if (_fout) { _animPath->write(_animPath->getTimeControlPointMap().find(animationPathTime), _fout); _fout.flush(); } } else _delta += delta; return true; } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): { // The user has requested to toggle recording. if (ea.getKey() ==_keyEventToggleRecord) { // The user has requested to BEGIN recording. if (!_currentlyRecording) { _currentlyRecording = true; _animStartTime = osg::Timer::instance()->tick(); _animPath = new osg::AnimationPath(); if (!_filename.empty()) { std::stringstream ss; ss << osgDB::getNameLessExtension(_filename); if ( _autoinc != -1 ) { ss << "_"<empty()) { // In the future this will need to be written continuously, rather // than all at once. osgDB::ofstream out(_filename.c_str()); OSG_NOTICE<<"Writing camera file: "<<_filename<write(out); out.close(); } else { OSG_NOTICE<<"No animation path to write out."<empty()) { _animPathManipulator = new osgGA::AnimationPathManipulator(_animPath.get()); _animPathManipulator->home(ea,aa); // If we successfully found our _filename file, set it and keep a copy // around of the original CameraManipulator to restore later. if (_animPathManipulator.valid() && _animPathManipulator->valid()) { _oldManipulator = view->getCameraManipulator(); view->setCameraManipulator(_animPathManipulator.get()); _currentlyPlaying = true; } } } // The user has requested to STOP playback. else { // Restore the old manipulator if necessary and stop playback. if(_oldManipulator.valid()) view->setCameraManipulator(_oldManipulator.get()); _currentlyPlaying = false; _oldManipulator = 0; } return true; } break; } default: break; } return false; } LODScaleHandler::LODScaleHandler(): _keyEventIncreaseLODScale('*'), _keyEventDecreaseLODScale('/') { } bool LODScaleHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { osgViewer::View* view = dynamic_cast(&aa); osg::Camera* camera = view ? view->getCamera() : 0; if (!camera) return false; if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): { if (ea.getKey() == _keyEventIncreaseLODScale) { camera->setLODScale(camera->getLODScale()*1.1); OSG_NOTICE<<"LODScale = "<getLODScale()<setLODScale(camera->getLODScale()/1.1); OSG_NOTICE<<"LODScale = "<getLODScale()<(&aa); if (!view) return false; osgViewer::ViewerBase* viewer = view->getViewerBase(); if (viewer == NULL) { return false; } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): { if (ea.getKey() == _keyEventToggleSyncToVBlank) { // Increase resolution osgViewer::Viewer::Windows windows; viewer->getWindows(windows); for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); itr != windows.end(); ++itr) { (*itr)->setSyncToVBlank( !(*itr)->getSyncToVBlank() ); } aa.requestRedraw(); return true; } break; } default: break; } return false; } void ToggleSyncToVBlankHandler::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding(_keyEventToggleSyncToVBlank,"Toggle SyncToVBlank."); } InteractiveImageHandler::InteractiveImageHandler(osg::Image* image) : _image(image), _texture(0), _fullscreen(false), _camera(0) { } InteractiveImageHandler::InteractiveImageHandler(osg::Image* image, osg::Texture2D* texture, osg::Camera* camera) : _image(image), _texture(texture), _fullscreen(true), _camera(camera) { if (_camera.valid() && _camera->getViewport()) { // Send an initial resize event (with the same size) so the image can // resize itself initially. double width = _camera->getViewport()->width(); double height = _camera->getViewport()->height(); resize(static_cast(width), static_cast(height)); } } bool InteractiveImageHandler::mousePosition(osgViewer::View* view, osg::NodeVisitor* nv, const osgGA::GUIEventAdapter& ea, int& x, int &y) const { if (!view) return false; if (_fullscreen) { x = (int) ea.getX(); y = (int) ea.getY(); return true; } osgUtil::LineSegmentIntersector::Intersections intersections; bool foundIntersection = (nv==0) ? view->computeIntersections(ea, intersections) : view->computeIntersections(ea, nv->getNodePath(), intersections); if (foundIntersection) { osg::Vec2 tc(0.5f,0.5f); // use the nearest intersection const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin()); osg::Drawable* drawable = intersection.drawable.get(); osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0; osg::Vec3Array* vertices = geometry ? dynamic_cast(geometry->getVertexArray()) : 0; if (vertices) { // get the vertex indices. const osgUtil::LineSegmentIntersector::Intersection::IndexList& indices = intersection.indexList; const osgUtil::LineSegmentIntersector::Intersection::RatioList& ratios = intersection.ratioList; if (indices.size()==3 && ratios.size()==3) { unsigned int i1 = indices[0]; unsigned int i2 = indices[1]; unsigned int i3 = indices[2]; float r1 = ratios[0]; float r2 = ratios[1]; float r3 = ratios[2]; osg::Array* texcoords = (geometry->getNumTexCoordArrays()>0) ? geometry->getTexCoordArray(0) : 0; osg::Vec2Array* texcoords_Vec2Array = dynamic_cast(texcoords); if (texcoords_Vec2Array) { // we have tex coord array so now we can compute the final tex coord at the point of intersection. osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1]; osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2]; osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3]; tc = tc1*r1 + tc2*r2 + tc3*r3; } } osg::TexMat* activeTexMat = 0; osg::Texture* activeTexture = 0; if (drawable->getStateSet()) { osg::TexMat* texMat = dynamic_cast(drawable->getStateSet()->getTextureAttribute(0,osg::StateAttribute::TEXMAT)); if (texMat) activeTexMat = texMat; osg::Texture* texture = dynamic_cast(drawable->getStateSet()->getTextureAttribute(0,osg::StateAttribute::TEXTURE)); if (texture) activeTexture = texture; } if (activeTexMat) { osg::Vec4 tc_transformed = osg::Vec4(tc.x(), tc.y(), 0.0f,0.0f) * activeTexMat->getMatrix(); tc.x() = tc_transformed.x(); tc.y() = tc_transformed.y(); } if (dynamic_cast(activeTexture)) { x = int( tc.x() ); y = int( tc.y() ); } else if (_image.valid()) { x = int( float(_image->s()) * tc.x() ); y = int( float(_image->t()) * tc.y() ); } return true; } } return false; } bool InteractiveImageHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv) { if (ea.getHandled()) return false; if (!_image) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::MOVE): case(osgGA::GUIEventAdapter::DRAG): case(osgGA::GUIEventAdapter::PUSH): case(osgGA::GUIEventAdapter::RELEASE): { osgViewer::View* view = dynamic_cast(&aa); int x,y; if (mousePosition(view, nv, ea, x, y)) { return _image->sendPointerEvent(x, y, ea.getButtonMask()); } break; } case(osgGA::GUIEventAdapter::KEYDOWN): case(osgGA::GUIEventAdapter::KEYUP): { osgViewer::View* view = dynamic_cast(&aa); int x,y; bool sendKeyEvent = mousePosition(view, nv, ea, x, y); if (sendKeyEvent) { return _image->sendKeyEvent(ea.getKey(), ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN); } break; } case (osgGA::GUIEventAdapter::RESIZE): { if (_fullscreen && _camera.valid()) { _camera->setViewport(0, 0, ea.getWindowWidth(), ea.getWindowHeight()); resize(ea.getWindowWidth(), ea.getWindowHeight()); return true; } break; } default: return false; } return false; } bool InteractiveImageHandler::cull(osg::NodeVisitor* nv, osg::Drawable*, osg::RenderInfo*) const { if (_image.valid()) { _image->setFrameLastRendered(nv->getFrameStamp()); } return false; } void InteractiveImageHandler::resize(int width, int height) { if (_image.valid()) { _image->scaleImage(width, height, 1); } // Make sure the texture does not rescale the image because // it thinks it should still be the previous size... if (_texture.valid()) _texture->setTextureSize(width, height); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/CMakeLists.txt0000644000175000017500000002452613151044751024374 0ustar albertoalberto# FIXME: For OS X, need flag for Framework or dylib IF(DYNAMIC_OPENSCENEGRAPH) ADD_DEFINITIONS(-DOSGVIEWER_LIBRARY) ELSE() ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) ENDIF() SET(LIB_NAME osgViewer) SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) FILE(GLOB CONFIG_HEADER_FILES ${HEADER_PATH}/config/*) FILE(GLOB CONFIG_SOURCE_FILES config/*.cpp) SET(TARGET_H ${HEADER_PATH}/CompositeViewer ${HEADER_PATH}/Export ${HEADER_PATH}/GraphicsWindow ${HEADER_PATH}/Keystone ${HEADER_PATH}/Renderer ${HEADER_PATH}/Scene ${HEADER_PATH}/Version ${HEADER_PATH}/View ${HEADER_PATH}/Viewer ${HEADER_PATH}/ViewerBase ${HEADER_PATH}/ViewerEventHandlers ) SET(LIB_COMMON_FILES ${CONFIG_SOURCE_FILES} CompositeViewer.cpp GraphicsWindow.cpp HelpHandler.cpp Keystone.cpp Renderer.cpp Scene.cpp ScreenCaptureHandler.cpp StatsHandler.cpp Version.cpp View.cpp Viewer.cpp ViewerBase.cpp ViewerEventHandlers.cpp ${OPENSCENEGRAPH_VERSIONINFO_RC} ) # Collect all the configuration files SET(LIB_EXTRA_LIBS) IF(WIN32 AND NOT ANDROID) # # Enable workaround for OpenGL driver issues when used in multithreaded/multiscreen with NVidia drivers on Windows XP # For example: osgviewer dumptruck.osg was showing total garbage (screen looked like shattered, splashed hedgehog) # There were also serious issues with render to texture cameras. # Workaround repeats makeCurrentContext call as it was found that this causes the problems to dissapear. # OPTION(OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND "Set to ON if you have NVidia board and drivers earlier than 177.92 ver" OFF) MARK_AS_ADVANCED(OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND) IF(OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND) ADD_DEFINITIONS(-DOSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND) ENDIF() SET(TARGET_H_NO_MODULE_INSTALL ${HEADER_PATH}/api/Win32/GraphicsHandleWin32 ${HEADER_PATH}/api/Win32/GraphicsWindowWin32 ${HEADER_PATH}/api/Win32/PixelBufferWin32 ) SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} GraphicsWindowWin32.cpp PixelBufferWin32.cpp ) ELSE() IF(APPLE AND NOT ANDROID) IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) SET(OSG_WINDOWING_SYSTEM "IOS" CACHE STRING "Windowing system type for graphics window creation, options only IOS.") ELSE() IF(${OSG_OSX_SDK_NAME} STREQUAL "macosx10.4" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.3" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.2" OR ${OSG_OSX_SDK_NAME} STREQUAL "macosx10.1") SET(OSG_WINDOWING_SYSTEM "Carbon" CACHE STRING "Windowing system type for graphics window creation, options Carbon, Cocoa or X11.") ELSE() SET(OSG_WINDOWING_SYSTEM "Cocoa" CACHE STRING "Windowing system type for graphics window creation, options Carbon, Cocoa or X11.") ENDIF() ENDIF() ELSE() IF(ANDROID) SET(OSG_WINDOWING_SYSTEM "None" CACHE STRING "None Windowing system type for graphics window creation.") ELSE() SET(OSG_WINDOWING_SYSTEM "X11" CACHE STRING "Windowing system type for graphics window creation. options only X11") ENDIF() ENDIF() IF(${OSG_WINDOWING_SYSTEM} STREQUAL "Cocoa") ADD_DEFINITIONS(-DUSE_DARWIN_COCOA_IMPLEMENTATION) IF(OSG_COMPILE_FRAMEWORKS) SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} ${HEADER_PATH}/api/Cocoa/GraphicsHandleCocoa ${HEADER_PATH}/api/Cocoa/GraphicsWindowCocoa ${HEADER_PATH}/api/Cocoa/PixelBufferCocoa ) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/Cocoa/GraphicsHandleCocoa PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/Cocoa) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/Cocoa/GraphicsWindowCocoa PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/Cocoa) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/Cocoa/PixelBufferCocoa PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/Cocoa) ELSE() SET(TARGET_H_NO_MODULE_INSTALL ${HEADER_PATH}/api/Cocoa/GraphicsHandleCocoa ${HEADER_PATH}/api/Cocoa/GraphicsWindowCocoa ${HEADER_PATH}/api/Cocoa/PixelBufferCocoa ) ENDIF() SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} GraphicsWindowCocoa.mm DarwinUtils.h DarwinUtils.mm PixelBufferCocoa.mm ) SET(LIB_EXTRA_LIBS ${COCOA_LIBRARY} ${LIB_EXTRA_LIBS}) ELSEIF(${OSG_WINDOWING_SYSTEM} STREQUAL "Carbon") ADD_DEFINITIONS(-DUSE_DARWIN_CARBON_IMPLEMENTATION) IF(OSG_COMPILE_FRAMEWORKS) SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} ${HEADER_PATH}/api/Carbon/GraphicsHandleCarbon ${HEADER_PATH}/api/Carbon/GraphicsWindowCarbon ${HEADER_PATH}/api/Carbon/PixelBufferCarbon ) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/Carbon/GraphicsHandleCarbon PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/Carbon) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/Carbon/GraphicsWindowCarbon PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/Carbon) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/Carbon/PixelBufferCarbon PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/Carbon) ELSE() SET(TARGET_H_NO_MODULE_INSTALL ${HEADER_PATH}/api/Carbon/GraphicsHandleCarbon ${HEADER_PATH}/api/Carbon/GraphicsWindowCarbon ${HEADER_PATH}/api/Carbon/PixelBufferCarbon ) ENDIF() SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} GraphicsWindowCarbon.cpp DarwinUtils.h DarwinUtils.mm PixelBufferCarbon.cpp ) SET(LIB_EXTRA_LIBS ${COCOA_LIBRARY} ${AGL_LIBRARY} ${LIB_EXTRA_LIBS}) ELSEIF(${OSG_WINDOWING_SYSTEM} STREQUAL "IOS") ADD_DEFINITIONS(-DUSE_IOS_IMPLEMENTATION) IF(OSG_COMPILE_FRAMEWORKS) SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} ${HEADER_PATH}/api/IOS/GraphicsWindowIOS ) SET_PROPERTY(SOURCE ${HEADER_PATH}/api/IOS/GraphicsWindowIOS PROPERTY MACOSX_PACKAGE_LOCATION Headers/api/IOS) ELSE() SET(TARGET_H_NO_MODULE_INSTALL ${HEADER_PATH}/api/IOS/GraphicsWindowIOS #${HEADER_PATH}/api/IOS/PixelBufferIOS ) ENDIF() SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} GraphicsWindowIOS.mm IOSUtils.h IOSUtils.mm ) SET(LIB_EXTRA_LIBS ${COCOA_LIBRARY} ${LIB_EXTRA_LIBS}) ELSEIF(${OSG_WINDOWING_SYSTEM} STREQUAL "X11") # X11 for everybody else INCLUDE(FindPkgConfig OPTIONAL) IF(PKG_CONFIG_FOUND) PKG_CHECK_MODULES(XRANDR xrandr) IF(XRANDR_FOUND) OPTION(OSGVIEWER_USE_XRANDR "Set to ON to enable Xrandr support for GraphicsWindowX11." ON) ELSE() SET(OSGVIEWER_USE_XRANDR OFF) ENDIF() ELSE() SET(OSGVIEWER_USE_XRANDR OFF) ENDIF() SET(TARGET_H_NO_MODULE_INSTALL ${HEADER_PATH}/api/X11/GraphicsHandleX11 ${HEADER_PATH}/api/X11/GraphicsWindowX11 ${HEADER_PATH}/api/X11/PixelBufferX11 ) SET(LIB_COMMON_FILES ${LIB_COMMON_FILES} GraphicsWindowX11.cpp PixelBufferX11.cpp ) IF(OSGVIEWER_USE_XRANDR) ADD_DEFINITIONS(-DOSGVIEWER_USE_XRANDR) SET(LIB_PRIVATE_HEADERS ${LIB_PRIVATE_HEADERS} ${XRANDR_INCLUDE_DIRS} ) IF(X11_Xrandr_LIB) SET(LIB_EXTRA_LIBS ${X11_Xrandr_LIB} ${LIB_EXTRA_LIBS}) ELSE() SET(LIB_EXTRA_LIBS ${XRANDR_LIBRARIES} ${LIB_EXTRA_LIBS}) ENDIF() ENDIF() # X11 on Apple requires X11 library plus OpenGL linking hack on Leopard IF(APPLE) # hack for finding the iphone opengl es lib IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) SET(OPENGL_INCLUDE_DIR ${IPHONE_SDKROOT}System/Library/Frameworks) SET(OPENGL_LIBRARIES ${IPHONE_SDKROOT}System/Library/Frameworks/OpenGLES) ELSE() # Find GL/glx.h IF(EXISTS ${CMAKE_OSX_SYSROOT}/usr/X11/include/GL/glx.h) SET(OPENGL_INCLUDE_DIR /usr/X11/include) SET(OPENGL_LIBRARIES /usr/X11/lib/libGL.dylib) ELSEIF(EXISTS ${CMAKE_OSX_SYSROOT}/usr/X11R6/include/GL/glx.h) SET(OPENGL_INCLUDE_DIR /usr/X11R6/include) SET(OPENGL_LIBRARIES /usr/X11R6/lib/libGL.dylib) ENDIF() INCLUDE_DIRECTORIES(BEFORE SYSTEM ${OPENGL_INCLUDE_DIR}) SET(LIB_EXTRA_LIBS ${X11_X11_LIB} ${OPENGL_LIBRARIES} ${LIB_EXTRA_LIBS}) SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib") ENDIF() ELSE(APPLE) SET(LIB_EXTRA_LIBS ${X11_X11_LIB} ${LIB_EXTRA_LIBS}) ENDIF(APPLE) ELSE() MESSAGE(STATUS "Windowing system not supported") ENDIF() ENDIF() SET(TARGET_SRC ${LIB_PRIVATE_HEADERS} ${LIB_COMMON_FILES} ) SET(TARGET_LIBRARIES osgGA osgText osgDB osgUtil osg OpenThreads ) SET(TARGET_EXTERNAL_LIBRARIES ${LIB_EXTRA_LIBS}) IF(MINGW OR CYGWIN) SET(TARGET_EXTERNAL_LIBRARIES ${TARGET_EXTERNAL_LIBRARIES} gdi32 ) ENDIF() SETUP_LIBRARY(${LIB_NAME}) # install these headers manually since setup_library and moduleinstall # wouldn't keep the structure, e.g. api/X11/xyz.h FOREACH(HEADERFILE ${TARGET_H_NO_MODULE_INSTALL} ${CONFIG_HEADER_FILES}) # get relative path to graphics system dependant header FILE(RELATIVE_PATH REL_INCLUDEFILE ${HEADER_PATH} ${HEADERFILE}) GET_FILENAME_COMPONENT(REL_INCLUDE_PATH ${REL_INCLUDEFILE} PATH) INSTALL(FILES ${HEADERFILE} DESTINATION ${INSTALL_INCDIR}/${LIB_NAME}/${REL_INCLUDE_PATH} COMPONENT libopenscenegraph-dev ) ENDFOREACH() # for structure in ide SOURCE_GROUP("${HEADERS_GROUP}\\api" FILES ${TARGET_H_NO_MODULE_INSTALL}) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/GraphicsWindowCocoa.mm0000644000175000017500000016367413151044751026074 0ustar albertoalberto/* * GraphicsWindowCocoa.cpp * OpenSceneGraph * * Created by Stephan Huber on 27.06.08. * Copyright 2008 Stephan Maximilian Huber, digital mind. All rights reserved. * * Some code borrowed from the implementation of CocoaViewer, * Created by Eric Wing on 11/12/06. and ported by Martin Lavery 7/06/07 * * Other snippets are borrowed from the Cocoa-implementation of the SDL-lib */ #include #include #include #include #include "DarwinUtils.h" //#define DEBUG_OUT(s) std::cout << "GraphicsWindowCocoa :: " << s << std::endl; #define DEBUG_OUT(s) ; static bool s_quit_requested = false; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 @interface NSApplication(NSAppleMenu) - (void)setAppleMenu:(NSMenu *)menu; @end #endif // ---------------------------------------------------------------------------------------------------------- // small helper class remapping key-codes // ---------------------------------------------------------------------------------------------------------- // small helper class which maps the raw key codes to osgGA::GUIEventAdapter::Keys class CocoaKeyboardMap { public: CocoaKeyboardMap() { _keymap[27] = osgGA::GUIEventAdapter::KEY_Escape; _keymap[13] = osgGA::GUIEventAdapter::KEY_Return; _keymap[3] = osgGA::GUIEventAdapter::KEY_KP_Enter; _keymap[9] = osgGA::GUIEventAdapter::KEY_Tab; _keymap[32] = osgGA::GUIEventAdapter::KEY_Space; _keymap[127] = osgGA::GUIEventAdapter::KEY_BackSpace; _keymap[NSHomeFunctionKey] = osgGA::GUIEventAdapter::KEY_Home; _keymap[NSEndFunctionKey] = osgGA::GUIEventAdapter::KEY_End; _keymap[NSPageUpFunctionKey] = osgGA::GUIEventAdapter::KEY_Page_Up; _keymap[NSPageDownFunctionKey] = osgGA::GUIEventAdapter::KEY_Page_Down; _keymap[NSLeftArrowFunctionKey] = osgGA::GUIEventAdapter::KEY_Left; _keymap[NSRightArrowFunctionKey] = osgGA::GUIEventAdapter::KEY_Right; _keymap[NSUpArrowFunctionKey] = osgGA::GUIEventAdapter::KEY_Up; _keymap[NSDownArrowFunctionKey] = osgGA::GUIEventAdapter::KEY_Down; _keymap[NSDeleteFunctionKey] = osgGA::GUIEventAdapter::KEY_Delete; _keymap[NSF1FunctionKey] = osgGA::GUIEventAdapter::KEY_F1; _keymap[NSF2FunctionKey] = osgGA::GUIEventAdapter::KEY_F2; _keymap[NSF3FunctionKey] = osgGA::GUIEventAdapter::KEY_F3; _keymap[NSF4FunctionKey] = osgGA::GUIEventAdapter::KEY_F4; _keymap[NSF5FunctionKey] = osgGA::GUIEventAdapter::KEY_F5; _keymap[NSF6FunctionKey] = osgGA::GUIEventAdapter::KEY_F6; _keymap[NSF7FunctionKey] = osgGA::GUIEventAdapter::KEY_F7; _keymap[NSF8FunctionKey] = osgGA::GUIEventAdapter::KEY_F8; _keymap[NSF9FunctionKey] = osgGA::GUIEventAdapter::KEY_F9; _keymap[NSF10FunctionKey] = osgGA::GUIEventAdapter::KEY_F10; _keymap[NSF11FunctionKey] = osgGA::GUIEventAdapter::KEY_F11; _keymap[NSF12FunctionKey] = osgGA::GUIEventAdapter::KEY_F12; _keymap[NSF13FunctionKey] = osgGA::GUIEventAdapter::KEY_F13; _keymap[NSF14FunctionKey] = osgGA::GUIEventAdapter::KEY_F14; _keymap[NSF15FunctionKey] = osgGA::GUIEventAdapter::KEY_F15; _keymap[NSF16FunctionKey] = osgGA::GUIEventAdapter::KEY_F16; _keymap[NSF17FunctionKey] = osgGA::GUIEventAdapter::KEY_F17; _keymap[NSF18FunctionKey] = osgGA::GUIEventAdapter::KEY_F18; _keymap[NSF19FunctionKey] = osgGA::GUIEventAdapter::KEY_F19; _keymap[NSF20FunctionKey] = osgGA::GUIEventAdapter::KEY_F20; _keymap[NSF21FunctionKey] = osgGA::GUIEventAdapter::KEY_F21; _keymap[NSF22FunctionKey] = osgGA::GUIEventAdapter::KEY_F22; _keymap[NSF23FunctionKey] = osgGA::GUIEventAdapter::KEY_F23; _keymap[NSF24FunctionKey] = osgGA::GUIEventAdapter::KEY_F24; _keymap[NSF25FunctionKey] = osgGA::GUIEventAdapter::KEY_F25; _keymap[NSF26FunctionKey] = osgGA::GUIEventAdapter::KEY_F26; _keymap[NSF27FunctionKey] = osgGA::GUIEventAdapter::KEY_F27; _keymap[NSF28FunctionKey] = osgGA::GUIEventAdapter::KEY_F28; _keymap[NSF29FunctionKey] = osgGA::GUIEventAdapter::KEY_F29; _keymap[NSF30FunctionKey] = osgGA::GUIEventAdapter::KEY_F30; _keymap[NSF31FunctionKey] = osgGA::GUIEventAdapter::KEY_F31; _keymap[NSF32FunctionKey] = osgGA::GUIEventAdapter::KEY_F32; _keymap[NSF33FunctionKey] = osgGA::GUIEventAdapter::KEY_F33; _keymap[NSF34FunctionKey] = osgGA::GUIEventAdapter::KEY_F34; _keymap[NSF35FunctionKey] = osgGA::GUIEventAdapter::KEY_F35; _keypadmap['='] = osgGA::GUIEventAdapter::KEY_KP_Equal; _keypadmap['*'] = osgGA::GUIEventAdapter::KEY_KP_Multiply; _keypadmap['+'] = osgGA::GUIEventAdapter::KEY_KP_Add; _keypadmap['-'] = osgGA::GUIEventAdapter::KEY_KP_Subtract; _keypadmap['.'] = osgGA::GUIEventAdapter::KEY_KP_Decimal; _keypadmap['/'] = osgGA::GUIEventAdapter::KEY_KP_Divide; _keypadmap['0'] = osgGA::GUIEventAdapter::KEY_KP_0; _keypadmap['1'] = osgGA::GUIEventAdapter::KEY_KP_1; _keypadmap['2'] = osgGA::GUIEventAdapter::KEY_KP_2; _keypadmap['3'] = osgGA::GUIEventAdapter::KEY_KP_3; _keypadmap['4'] = osgGA::GUIEventAdapter::KEY_KP_4; _keypadmap['5'] = osgGA::GUIEventAdapter::KEY_KP_5; _keypadmap['6'] = osgGA::GUIEventAdapter::KEY_KP_6; _keypadmap['7'] = osgGA::GUIEventAdapter::KEY_KP_7; _keypadmap['8'] = osgGA::GUIEventAdapter::KEY_KP_8; _keypadmap['9'] = osgGA::GUIEventAdapter::KEY_KP_9; } ~CocoaKeyboardMap() { } unsigned int remapKey(unsigned int key, bool pressedOnKeypad = false) { if (pressedOnKeypad) { KeyMap::iterator itr = _keypadmap.find(key); if (itr == _keypadmap.end()) return key; else return itr->second; } KeyMap::iterator itr = _keymap.find(key); if (itr == _keymap.end()) return key; else return itr->second; } private: typedef std::map KeyMap; KeyMap _keymap, _keypadmap; }; // ---------------------------------------------------------------------------------------------------------- // remapCocoaKey // ---------------------------------------------------------------------------------------------------------- static unsigned int remapCocoaKey(unsigned int key, unsigned int modifiers) { static CocoaKeyboardMap s_CocoaKeyboardMap; bool pressedOnKeypad = modifiers & NSNumericPadKeyMask; if (modifiers & NSFunctionKeyMask) pressedOnKeypad = false; //std::cout << std::hex << "remap " << key << " keypad: " << pressedOnKeypad << " modifiers: " << modifiers << std::endl; return s_CocoaKeyboardMap.remapKey(key, pressedOnKeypad); } std::ostream& operator<<(std::ostream& os, const NSRect& rect) { os << rect.origin.x << "/" << rect.origin.y << " " << rect.size.width << "x" << rect.size.height; return os; } // ---------------------------------------------------------------------------------------------------------- // Cocoa uses a coordinate system where its origin is in the bottom left corner, // osg and quartz uses top left for the origin // // these 2 methods convets rects between the different coordinate systems // ---------------------------------------------------------------------------------------------------------- static NSRect convertFromQuartzCoordinates(const NSRect& rect) { NSRect frame = [[[NSScreen screens] objectAtIndex: 0] frame]; float y = frame.size.height - rect.origin.y - rect.size.height; NSRect converted = NSMakeRect(rect.origin.x, y, rect.size.width, rect.size.height); // std::cout << "converting from Quartz " << rect << " to " << converted << " using screen rect " << frame << std::endl; return converted; } static NSRect convertToQuartzCoordinates(const NSRect& rect) { NSRect frame = [[[NSScreen screens] objectAtIndex: 0] frame]; float y = frame.size.height - (rect.origin.y + rect.size.height); NSRect converted = NSMakeRect(rect.origin.x, y, rect.size.width, rect.size.height); // std::cout << "converting To Quartz " << rect << " to " << converted << " using screen rect " << frame << std::endl; return converted; } #pragma mark CocoaAppDelegate // ---------------------------------------------------------------------------------------------------------- // the app-delegate, handling quit-requests // ---------------------------------------------------------------------------------------------------------- @interface CocoaAppDelegate : NSObject { } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification; @end @implementation CocoaAppDelegate - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { s_quit_requested = true; DEBUG_OUT("quit requested "); return NSTerminateNow; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { DEBUG_OUT("applicationDidFinishLaunching"); } @end #pragma mark GraphicsWindowCocoaWindow // ---------------------------------------------------------------------------------------------------------- // GraphicsWindowCocoaWindow, implements canBecomeKeyWindow + canBecomeMainWindow // ---------------------------------------------------------------------------------------------------------- @interface GraphicsWindowCocoaWindow : NSWindow { } - (BOOL) canBecomeKeyWindow; - (BOOL) canBecomeMainWindow; @end @implementation GraphicsWindowCocoaWindow - (BOOL) canBecomeKeyWindow { return YES; } - (BOOL) canBecomeMainWindow { return YES; } @end #pragma mark GraphicsWindowCocoaGLView // ---------------------------------------------------------------------------------------------------------- // GraphicsWindowCocoaGLView // custom NSOpenGLView-class handling mouse- and keyboard-events, forwarding them to the EventQueue // some code borrowed from the example osgCocoaViewer from E.Wing // ---------------------------------------------------------------------------------------------------------- @interface GraphicsWindowCocoaGLView : NSOpenGLView { @private osgViewer::GraphicsWindowCocoa* _win; BOOL _isUsingCtrlClick, _isUsingOptionClick; unsigned int _cachedModifierFlags; BOOL _handleTabletEvents; NSMutableDictionary* _touchPoints; unsigned int _lastTouchPointId; } - (void)setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; - (void)flagsChanged:(NSEvent *)theEvent; - (void) mouseMoved:(NSEvent*)theEvent; - (void) mouseDown:(NSEvent*)theEvent; - (void) mouseDragged:(NSEvent*)theEvent; - (void) mouseUp:(NSEvent*)theEvent; - (void) rightMouseDown:(NSEvent*)theEvent; - (void) rightMouseDragged:(NSEvent*)theEvent; - (void) rightMouseUp:(NSEvent*)theEvent; - (void) otherMouseDown:(NSEvent*)theEvent; - (void) otherMouseDragged:(NSEvent*)theEvent; - (void) otherMouseUp:(NSEvent*)theEvent; - (NSPoint) getLocalPoint: (NSEvent*)theEvent; - (void) handleModifiers: (NSEvent*)theEvent; - (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click; - (BOOL) isUsingCtrlClick; - (void) setIsUsingOptionClick:(BOOL)is_using_option_click; - (BOOL) isUsingOptionClick; - (void) doLeftMouseButtonDown:(NSEvent*)theEvent; - (void) doLeftMouseButtonUp:(NSEvent*)theEvent; - (void) doRightMouseButtonDown:(NSEvent*)theEvent; - (void) doRightMouseButtonUp:(NSEvent*)theEvent; - (void) doMiddleMouseButtonDown:(NSEvent*)theEvent; - (void) doExtraMouseButtonDown:(NSEvent*)theEvent buttonNumber:(int)button_number; - (void) doMiddleMouseButtonUp:(NSEvent*)theEvent; - (void) doExtraMouseButtonUp:(NSEvent*)theEvent buttonNumber:(int)button_number; - (void) scrollWheel:(NSEvent*)theEvent; - (void)tabletPoint:(NSEvent *)theEvent; - (void)tabletProximity:(NSEvent *)theEvent; - (void)handleTabletEvents:(NSEvent*)theEvent; #if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) - (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (NSTouchPhase) phase; - (unsigned int)computeTouchId: (NSTouch*) touch mayCleanup: (BOOL) may_cleanup; - (void)touchesBeganWithEvent:(NSEvent *)event; - (void)touchesMovedWithEvent:(NSEvent *)event; - (void)touchesEndedWithEvent:(NSEvent *)event; - (void)touchesCancelledWithEvent:(NSEvent *)event; #endif - (BOOL)useMultiTouchOnly: (NSEvent*) event; - (BOOL)acceptsFirstResponder; - (BOOL)becomeFirstResponder; - (BOOL)resignFirstResponder; - (void)dealloc; @end @implementation GraphicsWindowCocoaGLView -(void) setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win { _win = win; _touchPoints = NULL; } -(void) dealloc { if (_touchPoints) [_touchPoints release]; [super dealloc]; } - (BOOL)acceptsFirstResponder { return YES; } - (BOOL)becomeFirstResponder { return YES; } - (BOOL)resignFirstResponder { return YES; } - (BOOL) useMultiTouchOnly: (NSEvent*) event { #if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) return ([self acceptsTouchEvents] && ([event subtype] == NSTouchEventSubtype)); #else return false; #endif } - (NSPoint) getLocalPoint: (NSEvent*)theEvent { return [self convertPoint:[theEvent locationInWindow] fromView:nil]; } - (void) handleModifiers: (NSEvent*)theEvent { DEBUG_OUT("handling modifiers"); if ((!_win) || (!_win->getEventQueue())) return; // no event queue in place unsigned int flags = [theEvent modifierFlags]; if (flags == _cachedModifierFlags) return; const unsigned int masks[] = { NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask, NSCommandKeyMask, NSAlphaShiftKeyMask }; const unsigned int keys[] = { osgGA::GUIEventAdapter::KEY_Shift_L, osgGA::GUIEventAdapter::KEY_Control_L, osgGA::GUIEventAdapter::KEY_Alt_L, osgGA::GUIEventAdapter::KEY_Super_L, osgGA::GUIEventAdapter::KEY_Caps_Lock }; // std::cout << "flags: " << flags << " cached: " << _cachedModifierFlags << std::endl; for(unsigned int i = 0; i < 5; ++i) { if ((flags & masks[i]) && !(_cachedModifierFlags & masks[i])) { _win->getEventQueue()->keyPress(keys[i], _win->getEventQueue()->getTime(), keys[i]); // we don't get a key up for the caps lock so emulate it. if (i == 4) _win->getEventQueue()->keyRelease(keys[i], _win->getEventQueue()->getTime(), keys[i]); } if (!(flags & masks[i]) && (_cachedModifierFlags & masks[i])) { if (i == 4) { // emulate a key down for caps-lock. _win->getEventQueue()->keyPress(keys[i], _win->getEventQueue()->getTime(), keys[i]); } _win->getEventQueue()->keyRelease(keys[i], _win->getEventQueue()->getTime(), keys[i]); } } _cachedModifierFlags = flags; } - (void)flagsChanged:(NSEvent *)theEvent { [self handleModifiers: theEvent]; } - (void) mouseMoved:(NSEvent*)theEvent { // if multitouch is enabled, disable standard event handling if ([self useMultiTouchOnly: theEvent]) return; NSPoint converted_point = [self getLocalPoint: theEvent]; DEBUG_OUT("Mouse moved" << converted_point.x << "/" << converted_point.y); _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); } - (void) mouseDown:(NSEvent*)theEvent { // if multitouch is enabled, disable standard event handling if ([self useMultiTouchOnly: theEvent]) return; DEBUG_OUT("Mouse down"); // Because many Mac users have only a 1-button mouse, we should provide ways // to access the button 2 and 3 actions of osgViewer. // I will use the Ctrl modifer to represent right-clicking // and Option modifier to represent middle clicking. if([theEvent modifierFlags] & NSControlKeyMask) { [self setIsUsingCtrlClick:YES]; [self doRightMouseButtonDown:theEvent]; } else if([theEvent modifierFlags] & NSAlternateKeyMask) { [self setIsUsingOptionClick:YES]; [self doMiddleMouseButtonDown:theEvent]; } else { [self doLeftMouseButtonDown:theEvent]; } if ([theEvent subtype] == NSTabletPointEventSubtype) { _handleTabletEvents = true; [self handleTabletEvents:theEvent]; } } - (void) mouseDragged:(NSEvent*)theEvent { // if multitouch is enabled, disable standard event handling if ([self useMultiTouchOnly: theEvent]) return; if (!_win) return; NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); if (_handleTabletEvents) [self handleTabletEvents:theEvent]; } - (void) mouseUp:(NSEvent*)theEvent { // if multitouch is enabled, disable standard event handling if ([self useMultiTouchOnly: theEvent]) return; // Because many Mac users have only a 1-button mouse, we should provide ways // to access the button 2 and 3 actions of osgViewer. // I will use the Ctrl modifer to represent right-clicking // and Option modifier to represent middle clicking. if([self isUsingCtrlClick] == YES) { [self setIsUsingCtrlClick:NO]; [self doRightMouseButtonUp:theEvent]; } else if([self isUsingOptionClick] == YES) { [self setIsUsingOptionClick:NO]; [self doMiddleMouseButtonUp:theEvent]; } else { [self doLeftMouseButtonUp:theEvent]; } _handleTabletEvents = false; } - (void) rightMouseDown:(NSEvent*)theEvent { [self doRightMouseButtonDown:theEvent]; } - (void) rightMouseDragged:(NSEvent*)theEvent { if (!_win) return; NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); } - (void) rightMouseUp:(NSEvent*)theEvent { [self doRightMouseButtonUp:theEvent]; _handleTabletEvents = false; } // "otherMouse" seems to capture middle button and any other buttons beyond (4th, etc). - (void) otherMouseDown:(NSEvent*)theEvent { // Button 0 is left // Button 1 is right // Button 2 is middle // Button 3 keeps going // osgViewer expects 1 for left, 3 for right, 2 for middle // osgViewer has a reversed number mapping for right and middle compared to Cocoa if([theEvent buttonNumber] == 2) { [self doMiddleMouseButtonDown:theEvent]; } else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer { [self doExtraMouseButtonDown:theEvent buttonNumber:[theEvent buttonNumber]]; } } - (void) otherMouseDragged:(NSEvent*)theEvent { if (!_win) return; NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); } // "otherMouse" seems to capture middle button and any other buttons beyond (4th, etc). - (void) otherMouseUp:(NSEvent*)theEvent { // Button 0 is left // Button 1 is right // Button 2 is middle // Button 3 keeps going // osgViewer expects 1 for left, 3 for right, 2 for middle // osgViewer has a reversed number mapping for right and middle compared to Cocoa if([theEvent buttonNumber] == 2) { [self doMiddleMouseButtonUp:theEvent]; } else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer { // I don't think osgViewer does anything for these additional buttons, // but just in case, pass them along. But as a Cocoa programmer, you might // think about things you can do natively here instead of passing the buck. [self doExtraMouseButtonUp:theEvent buttonNumber:[theEvent buttonNumber]]; } } - (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click { _isUsingCtrlClick = is_using_ctrl_click; } - (BOOL) isUsingCtrlClick { return _isUsingCtrlClick; } - (void) setIsUsingOptionClick:(BOOL)is_using_option_click { _isUsingOptionClick = is_using_option_click; } - (BOOL) isUsingOptionClick { return _isUsingOptionClick; } - (void)doSingleOrDoubleButtonPress:(NSEvent*)event forButton:(int)button { if (!_win) { return; } NSPoint convertedPoint = [self getLocalPoint:event]; if ([event clickCount] == 1) { _win->getEventQueue()->mouseButtonPress(convertedPoint.x, convertedPoint.y, button); } else { _win->getEventQueue()->mouseDoubleButtonPress(convertedPoint.x, convertedPoint.y, button); } //[self setNeedsDisplay:YES]; } - (void)doButtonRelease:(NSEvent*)event forButton:(int)button { if (!_win) { return; } NSPoint convertedPoint = [self getLocalPoint:event]; _win->getEventQueue()->mouseButtonRelease(convertedPoint.x, convertedPoint.y, button); //[self setNeedsDisplay:YES]; } // Left mouse button - (void) doLeftMouseButtonDown:(NSEvent*)theEvent { [self doSingleOrDoubleButtonPress:theEvent forButton:1]; } - (void) doLeftMouseButtonUp:(NSEvent*)theEvent { [self doButtonRelease:theEvent forButton:1]; } // Right mouse button - (void) doRightMouseButtonDown:(NSEvent*)theEvent { [self doSingleOrDoubleButtonPress:theEvent forButton:3]; } - (void) doRightMouseButtonUp:(NSEvent*)theEvent { [self doButtonRelease:theEvent forButton:3]; } // Middle mouse button - (void) doMiddleMouseButtonDown:(NSEvent*)theEvent { [self doSingleOrDoubleButtonPress:theEvent forButton:2]; } - (void) doMiddleMouseButtonUp:(NSEvent*)theEvent { [self doButtonRelease:theEvent forButton:2]; } // Extra mouse buttons - (void) doExtraMouseButtonDown:(NSEvent*)theEvent buttonNumber:(int)button_number { [self doButtonRelease:theEvent forButton:(button_number+1)]; } - (void) doExtraMouseButtonUp:(NSEvent*)theEvent buttonNumber:(int)button_number { [self doButtonRelease:theEvent forButton:(button_number+1)]; } - (void) scrollWheel:(NSEvent*)theEvent { if (!_win) return; // Unfortunately, it turns out mouseScroll2D doesn't actually do anything. // The camera manipulators don't seem to implement any code that utilize the scroll values. // This this call does nothing. _win->getEventQueue()->mouseScroll2D([theEvent deltaX], [theEvent deltaY]); } - (void)keyDown:(NSEvent *)theEvent { if (!_win) return; NSString* unmodified_chars = [theEvent charactersIgnoringModifiers]; if ([theEvent modifierFlags] && NSShiftKeyMask) { unmodified_chars = [unmodified_chars lowercaseString]; } NSString* chars = [theEvent characters]; if ((chars) && ([chars length] > 0)) { unsigned int unmodified_keyCode = remapCocoaKey([unmodified_chars characterAtIndex:0], [theEvent modifierFlags] ); unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], [theEvent modifierFlags] ); //std::cout << std::hex << "key dn: " <<[chars characterAtIndex:0] << "=" << keyCode << " unmodified: " << unmodified_keyCode << std::endl; _win->getEventQueue()->keyPress( keyCode, _win->getEventQueue()->getTime(), unmodified_keyCode); } } - (void)keyUp:(NSEvent *)theEvent { if (!_win) return; NSString* unmodified_chars = [theEvent charactersIgnoringModifiers]; if ([theEvent modifierFlags] && NSShiftKeyMask) { unmodified_chars = [unmodified_chars lowercaseString]; } NSString* chars = [theEvent characters]; if ((chars) && ([chars length] > 0)) { unsigned int unmodified_keyCode = remapCocoaKey([unmodified_chars characterAtIndex:0], [theEvent modifierFlags] ); unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], [theEvent modifierFlags] ); //std::cout << std::hex << "key up: " <<[chars characterAtIndex:0] << "=" << keyCode << " unmodified: " << unmodified_keyCode << std::endl; _win->getEventQueue()->keyRelease( keyCode, _win->getEventQueue()->getTime(), unmodified_keyCode); } } - (void)tabletPoint:(NSEvent *)theEvent { //_handleTabletEvents = YES; //[self handleTabletEvents:theEvent]; } -(void)handleTabletEvents:(NSEvent *)theEvent { if (!_win) return; float pressure = [theEvent pressure]; _win->getEventQueue()->penPressure(pressure); NSPoint tilt = [theEvent tilt]; _win->getEventQueue()->penOrientation (tilt.x, tilt.y, [theEvent rotation]); } - (void)tabletProximity:(NSEvent *)theEvent { if (!_win) return; osgGA::GUIEventAdapter::TabletPointerType pt(osgGA::GUIEventAdapter::UNKNOWN); switch ([theEvent pointingDeviceType]) { case NSPenPointingDevice: pt = osgGA::GUIEventAdapter::PEN; break; case NSCursorPointingDevice: pt = osgGA::GUIEventAdapter::PUCK; break; case NSEraserPointingDevice: pt = osgGA::GUIEventAdapter::ERASER; break; default: break; } _win->getEventQueue()->penProximity(pt, [theEvent isEnteringProximity]); } #if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) - (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (NSTouchPhase) phase { switch(phase) { case NSTouchPhaseBegan: return osgGA::GUIEventAdapter::TOUCH_BEGAN; break; case NSTouchPhaseMoved: return osgGA::GUIEventAdapter::TOUCH_MOVED; break; case NSTouchPhaseStationary: return osgGA::GUIEventAdapter::TOUCH_STATIONERY; break; case NSTouchPhaseEnded: case NSTouchPhaseCancelled: return osgGA::GUIEventAdapter::TOUCH_ENDED; break; } return osgGA::GUIEventAdapter::TOUCH_ENDED; } - (unsigned int)computeTouchId: (NSTouch*) touch mayCleanup: (BOOL) may_cleanup { unsigned int result(0); if(!_touchPoints) { _touchPoints = [[NSMutableDictionary alloc] init]; _lastTouchPointId = 0; } switch([touch phase]) { case NSTouchPhaseBegan: if ([_touchPoints objectForKey: [touch identity]] == nil) { [_touchPoints setObject: [NSNumber numberWithInt: _lastTouchPointId] forKey: [touch identity]]; result = _lastTouchPointId++; break; } // missing "break" by intention! case NSTouchPhaseMoved: case NSTouchPhaseStationary: { NSNumber* n = [_touchPoints objectForKey: [touch identity]]; result = [n intValue]; } break; case NSTouchPhaseEnded: case NSTouchPhaseCancelled: { NSNumber* n = [_touchPoints objectForKey: [touch identity]]; result = [n intValue]; if(may_cleanup) [_touchPoints removeObjectForKey: [touch identity]]; if([_touchPoints count] == 0) { _lastTouchPointId = 0; } } break; default: break; } return result; } - (void)touchesBeganWithEvent:(NSEvent *)event { NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; osg::ref_ptr osg_event(NULL); NSRect bounds = [self bounds]; for(unsigned int i=0; i<[allTouches count]; i++) { NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; NSPoint pos = [touch normalizedPosition]; pos.x *= bounds.size.width; pos.y *= bounds.size.height; unsigned int touch_id = [self computeTouchId: touch mayCleanup:FALSE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); osg_event->setInputRange(0, 0, bounds.size.width, bounds.size.height); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y); } } } - (void)touchesMovedWithEvent:(NSEvent *)event { NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; osg::ref_ptr osg_event(NULL); NSRect bounds = [self bounds]; for(unsigned int i=0; i<[allTouches count]; i++) { NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; NSPoint pos = [touch normalizedPosition]; pos.x *= bounds.size.width; pos.y *= bounds.size.height; unsigned int touch_id = [self computeTouchId: touch mayCleanup:FALSE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); osg_event->setInputRange(0, 0, bounds.size.width, bounds.size.height); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y); } } } - (void)touchesEndedWithEvent:(NSEvent *)event { NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; osg::ref_ptr osg_event(NULL); NSRect bounds = [self bounds]; for(unsigned int i=0; i<[allTouches count]; i++) { NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; NSPoint pos = [touch normalizedPosition]; pos.x *= bounds.size.width; pos.y *= bounds.size.height; unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y, 1); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); osg_event->setInputRange(0, 0, bounds.size.width, bounds.size.height); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y, 1); } } } - (void)touchesCancelledWithEvent:(NSEvent *)event { [self touchesEndedWithEvent: event]; } #endif @end #pragma mark GraphicsWindowCocoaDelegate #ifndef MAC_OS_X_VERSION_10_6 #define MAC_OS_X_VERSION_10_6 1060 #endif // ---------------------------------------------------------------------------------------------------------- // the window-delegate, handles moving/resizing of the window etc. // ---------------------------------------------------------------------------------------------------------- @interface GraphicsWindowCocoaDelegate : NSObject #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 #endif { @private osgViewer::GraphicsWindowCocoa* _win; BOOL _inDidMove; } - (id)initWith: (osgViewer::GraphicsWindowCocoa*) win; - (void)windowDidMove:(NSNotification *)notification; - (void)windowDidResize:(NSNotification *)notification; - (BOOL)windowShouldClose:(id)window; - (void)updateWindowBounds; @end @implementation GraphicsWindowCocoaDelegate - (id)initWith: (osgViewer::GraphicsWindowCocoa*) win { _inDidMove = false; _win = win; return [super init]; } - (void)windowDidMove:(NSNotification *)notification { [self updateWindowBounds]; } - (void)windowDidResize:(NSNotification *)notification { [self updateWindowBounds]; } -(void)updateWindowBounds { if (_inDidMove) return; _inDidMove = true; GraphicsWindowCocoaWindow* nswin = _win->getWindow(); NSRect bounds = [nswin contentRectForFrameRect: [nswin frame] ]; // convert to quartz-coordinate-system bounds = convertToQuartzCoordinates(bounds); // std::cout << "windowdidmove: " << bounds.origin.x << " " << bounds.origin.y << " " << bounds.size.width << " " << bounds.size.height << std::endl; _win->adaptResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); //_win->getEventQueue()->windowResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height, _win->getEventQueue()->getTime()); _win->requestRedraw(); _inDidMove = false; } - (BOOL)windowShouldClose:(id)window { return _win->requestClose(); } @end #pragma mark CocoaWindowAdapter using namespace osgDarwin; namespace osgViewer { // ---------------------------------------------------------------------------------------------------------- // small adapter class to handle the dock/menubar // ---------------------------------------------------------------------------------------------------------- class CocoaWindowAdapter : public MenubarController::WindowAdapter { public: CocoaWindowAdapter(GraphicsWindowCocoa* win) : MenubarController::WindowAdapter(), _win(win) {} virtual bool valid() { return (_win.valid() && _win->valid()); } virtual void getWindowBounds(CGRect& rect) { NSRect nsrect = [_win->getWindow() frame]; nsrect = convertToQuartzCoordinates(nsrect); rect.origin.x = nsrect.origin.x; rect.origin.y = nsrect.origin.y; rect.size.width = nsrect.size.width; rect.size.height = nsrect.size.height; } virtual osgViewer::GraphicsWindow* getWindow() {return _win.get(); } private: osg::observer_ptr _win; }; #pragma mark GraphicsWindowCocoa // ---------------------------------------------------------------------------------------------------------- // init // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::init() { if (_initialized) return; _closeRequested = false; _ownsWindow = false; _context = NULL; _window = NULL; _pixelformat = NULL; _updateContext = false; _valid = _initialized = true; // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); } // ---------------------------------------------------------------------------------------------------------- // setupNSWindow // sets up the NSWindow, adds delegates, etc // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::setupNSWindow(NSWindow* win) { [win setReleasedWhenClosed:NO]; [win setDisplaysWhenScreenProfileChanges:YES]; GraphicsWindowCocoaDelegate* delegate = [[GraphicsWindowCocoaDelegate alloc] initWith: this]; [win setDelegate: delegate ]; //[delegate autorelease]; [win makeKeyAndOrderFront:nil]; [win setAcceptsMouseMovedEvents: YES]; } // ---------------------------------------------------------------------------------------------------------- // realizeImplementation, creates the window + context // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa::realizeImplementation() { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; unsigned int style(NSBorderlessWindowMask); if (_traits->windowDecoration) { style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask; // supportsResize works only with windows with titlebar if (_traits->supportsResize) style |= NSResizableWindowMask; } DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); int screenLeft(0), screenTop(0); if (wsi) { wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); } NSRect rect = NSMakeRect(_traits->x + screenLeft, _traits->y + screenTop, _traits->width, _traits->height); _ownsWindow = true; // should we create a NSView only?? WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast(_traits->inheritedWindowData.get()) : NULL; if (windowData) { if (windowData->createOnlyView()) _ownsWindow = false; _checkForEvents = windowData->checkForEvents(); } OSG_DEBUG << "GraphicsWindowCocoa::realizeImplementation / ownsWindow: " << _ownsWindow << " checkForEvents: " << _checkForEvents << std::endl; if (_ownsWindow) { _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO]; if (!_window) { OSG_WARN << "GraphicsWindowCocoa::realizeImplementation :: could not create window" << std::endl; return false; } rect = convertFromQuartzCoordinates(rect); [_window setFrameOrigin: rect.origin]; } NSOpenGLPixelFormatAttribute attr[32]; int i = 0; attr[i++] = NSOpenGLPFADepthSize; attr[i++] = static_cast(_traits->depth); if (_traits->doubleBuffer) { attr[i++] = NSOpenGLPFADoubleBuffer; } if (_traits->alpha) { attr[i++] = NSOpenGLPFAAlphaSize; attr[i++] = static_cast(_traits->alpha); } if (_traits->stencil) { attr[i++] = NSOpenGLPFAStencilSize; attr[i++] = static_cast(_traits->stencil); } if (_traits->sampleBuffers) { attr[i++] = NSOpenGLPFASampleBuffers; attr[i++] = static_cast(_traits->sampleBuffers); attr[i++] = NSOpenGLPFASamples; attr[i++] = static_cast(_traits->samples); } attr[i++] = NSOpenGLPFAAccelerated; attr[i] = static_cast(0); // create the context NSOpenGLContext* sharedContext = NULL; GraphicsHandleCocoa* graphicsHandleCocoa = dynamic_cast(_traits->sharedContext.get()); if (graphicsHandleCocoa) { sharedContext = graphicsHandleCocoa->getNSOpenGLContext(); } _pixelformat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr ]; _context = [[NSOpenGLContext alloc] initWithFormat: _pixelformat shareContext: sharedContext]; if (!_context) { OSG_WARN << "GraphicsWindowCocoa::realizeImplementation :: could not create context" << std::endl; return false; } // set graphics handle for shared usage setNSOpenGLContext(_context); _view = [[ GraphicsWindowCocoaGLView alloc ] initWithFrame:[ _window frame ] ]; [_view setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable) ]; [_view setGraphicsWindowCocoa: this]; [_view setOpenGLContext:_context]; // enable multitouch if (_multiTouchEnabled || (windowData && windowData->isMultiTouchEnabled())) { setMultiTouchEnabled(true); } OSG_DEBUG << "GraphicsWindowCocoa::realizeImplementation / view: " << _view << std::endl; if (_ownsWindow) { [_window setContentView: _view]; setupNSWindow(_window); [_view release]; MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) ); } else { windowData->setCreatedNSView(_view); } [pool release]; useCursor(_traits->useCursor); setWindowName(_traits->windowName); setSyncToVBlank(_traits->vsync); MenubarController::instance()->update(); // Cocoa's origin is bottom/left: getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); _valid = _initialized = _realized = true; return _valid; } // ---------------------------------------------------------------------------------------------------------- // closeImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::closeImplementation() { _valid = false; _realized = false; // there's a possibility that the MenubarController is destructed already, so prevent a crash: MenubarController* mbc = MenubarController::instance(); if (mbc) mbc->detachWindow(this); if (_view) { [_view setGraphicsWindowCocoa: NULL]; } if (_window) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // we have to close + release the window in the main-thread [_window performSelectorOnMainThread: @selector(close) withObject:NULL waitUntilDone: YES]; [_window performSelectorOnMainThread: @selector(release) withObject:NULL waitUntilDone: YES]; [pool release]; } _window = NULL; _view = NULL; } // ---------------------------------------------------------------------------------------------------------- // makeCurrentImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa:: makeCurrentImplementation() { if (_updateContext) { [_context update]; _updateContext = false; } [_context makeCurrentContext]; return true; } // ---------------------------------------------------------------------------------------------------------- // releaseContextImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa::releaseContextImplementation() { [NSOpenGLContext clearCurrentContext]; return true; } // ---------------------------------------------------------------------------------------------------------- // swapBuffersImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::swapBuffersImplementation() { [_context flushBuffer]; } // ---------------------------------------------------------------------------------------------------------- // checkEvents // process all pending events // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa::checkEvents() { if (!_checkForEvents) return false; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; while(1) { /* NOTE: It may be better to use something like NSEventTrackingRunLoopMode since we don't necessarily want all timers/sources/observers to run, only those which would run while tracking events. However, it should be noted that NSEventTrackingRunLoopMode is in the common set of modes so it may not effectively make much of a difference. */ NSEvent *event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue: YES]; if(!event) break; [NSApp sendEvent: event]; } if (_closeRequested) getEventQueue()->closeWindow(); if (s_quit_requested) { getEventQueue()->quitApplication(); s_quit_requested = false; } [pool release]; return !(getEventQueue()->empty()); } // ---------------------------------------------------------------------------------------------------------- // setWindowDecorationImplementation // // unfortunately there's no way to change the decoration of a window, so we create an new one // and swap the content // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag) { if (!_realized || !_ownsWindow) return false; NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; unsigned int style(NSBorderlessWindowMask); if (flag) { style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask; // supportsResize works only with windows with titlebar if (_traits->supportsResize) style |= NSResizableWindowMask; } NSRect rect = [_window contentRectForFrameRect: [_window frame] ]; GraphicsWindowCocoaWindow* new_win = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO]; if (new_win) { [new_win setContentView: [_window contentView]]; setupNSWindow(new_win); NSString* title = (_traits.valid()) ? [NSString stringWithUTF8String: _traits->windowName.c_str()] : @""; [new_win setTitle: title ]; [_window close]; [_window release]; _window = new_win; [_window makeKeyAndOrderFront: nil]; } [localPool release]; return true; } // ---------------------------------------------------------------------------------------------------------- // grabFocus // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::grabFocus() { if (_ownsWindow) [_window makeKeyAndOrderFront: nil]; } // ---------------------------------------------------------------------------------------------------------- // grabFocusIfPointerInWindow // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::grabFocusIfPointerInWindow() { OSG_INFO << "GraphicsWindowCocoa :: grabFocusIfPointerInWindow not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // resizedImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int height) { DEBUG_OUT("resized implementation" << x << " " << y << " " << width << " " << height); GraphicsContext::resizedImplementation(x, y, width, height); _updateContext = true; MenubarController::instance()->update(); getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime()); } // ---------------------------------------------------------------------------------------------------------- // setWindowRectangleImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int width, int height) { if (!_ownsWindow) return false; NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); int screenLeft(0), screenTop(0); if (wsi) { wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); } NSRect rect = NSMakeRect(x+screenLeft,y+screenTop,width, height); rect = convertFromQuartzCoordinates(rect); [_window setFrame: [NSWindow frameRectForContentRect: rect styleMask: [_window styleMask]] display: YES]; [_context update]; MenubarController::instance()->update(); [localPool release]; return true; } // ---------------------------------------------------------------------------------------------------------- // // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::adaptResize(int x, int y, int w, int h) { DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); int screenLeft(0), screenTop(0); if (wsi) { // get the screen containing the window unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h); // update traits _traits->screenNum = screenNdx; // get top left of screen wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); } resized(x-screenLeft,y-screenTop,w,h); getEventQueue()->windowResize(x-screenLeft, y-screenTop, w, h, getEventQueue()->getTime()); } // ---------------------------------------------------------------------------------------------------------- // setWindowName // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::setWindowName (const std::string & name) { if (_traits.valid()) _traits->windowName = name; if (!_ownsWindow) return; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString* title = [NSString stringWithUTF8String: name.c_str()]; [_window setTitle: title]; [pool release]; } // ---------------------------------------------------------------------------------------------------------- // requestWarpPointer // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::requestWarpPointer(float x,float y) { CGPoint point; point.x = x + _traits->x; point.y = y + _traits->y; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 CGEventRef warpEvent = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, point, kCGMouseButtonLeft); CGEventPost(kCGHIDEventTap, warpEvent); CFRelease(warpEvent); #else DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi == NULL) { osg::notify(osg::WARN) << "GraphicsWindowCocoa::useCursor :: could not get OSXCocoaWindowingSystemInterface" << std::endl; return; } CGDirectDisplayID displayId = wsi->getDisplayID((*_traits)); CGSetLocalEventsSuppressionInterval(0); CGDisplayMoveCursorToPoint(displayId, point); #endif getEventQueue()->mouseWarped(x,y); } // ---------------------------------------------------------------------------------------------------------- // useCursor // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::useCursor(bool cursorOn) { if (_traits.valid()) _traits->useCursor = cursorOn; DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi == NULL) { OSG_WARN << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl; return; } CGDirectDisplayID displayId = wsi->getDisplayID((*_traits)); CGDisplayErr err = kCGErrorSuccess; if (cursorOn) { err = CGDisplayShowCursor(displayId); } else { err = CGDisplayHideCursor(displayId); } if (err != kCGErrorSuccess) { OSG_WARN << "GraphicsWindowCocoa::useCursor failed with " << err << std::endl; } } // ---------------------------------------------------------------------------------------------------------- // setCursor // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor) { if (_currentCursor == mouseCursor) { return; } NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; switch (mouseCursor) { case NoCursor: [NSCursor hide]; break; case LeftArrowCursor: case RightArrowCursor: [[NSCursor arrowCursor] set]; break; case TextCursor: [[NSCursor IBeamCursor] set]; break; case CrosshairCursor: [[NSCursor crosshairCursor] set]; break; default: OSG_INFO << "GraphicsWindowCocoa::setCursor :: unsupported MouseCursor: " << mouseCursor << std::endl; } if (_currentCursor == NoCursor) { [NSCursor unhide]; } _currentCursor = mouseCursor; [localPool release]; } // ---------------------------------------------------------------------------------------------------------- // setSyncToVBlank // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::setSyncToVBlank(bool f) { if (_traits.valid()) _traits->vsync = f; GLint VBL(f?1:0); [_context setValues:&VBL forParameter:NSOpenGLCPSwapInterval]; } bool GraphicsWindowCocoa::isMultiTouchEnabled() { return _multiTouchEnabled; } void GraphicsWindowCocoa::setMultiTouchEnabled(bool b) { _multiTouchEnabled = b; #if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) if (_view) [_view setAcceptsTouchEvents: b]; #else if (b) { OSG_WARN << "GraphicsWindowCocoa :: multi-touch only available for OS X >= 10.6, please check your compile settings" << std::endl; } #endif } // ---------------------------------------------------------------------------------------------------------- // d'tor // ---------------------------------------------------------------------------------------------------------- GraphicsWindowCocoa::~GraphicsWindowCocoa() { close(); } #pragma mark CocoaWindowingSystemInterface // ---------------------------------------------------------------------------------------------------------- // CocoaWindowingSystemInterface // ---------------------------------------------------------------------------------------------------------- struct CocoaWindowingSystemInterface : public DarwinWindowingSystemInterface { CocoaWindowingSystemInterface() : DarwinWindowingSystemInterface() { } void initAsStandaloneApplication() { _init(); static bool s_inited = false; if (s_inited) return; s_inited = true; OSG_INFO << "CocoaWindowingSystemInterface::initAsStandaloneApplication " << std::endl; ProcessSerialNumber psn; if (!GetCurrentProcess(&psn)) { TransformProcessType(&psn, kProcessTransformToForegroundApplication); SetFrontProcess(&psn); } NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; if (NSApp == nil) { [NSApplication sharedApplication]; } [NSApp setDelegate: [[CocoaAppDelegate alloc] init] ]; createApplicationMenus(); [NSApp finishLaunching]; [localPool release]; } virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) { _init(); if (!traits->pbuffer) { GraphicsWindowCocoa::WindowData* windowData = traits->inheritedWindowData ? dynamic_cast(traits->inheritedWindowData.get()) : NULL; if (!windowData || (windowData && windowData->poseAsStandaloneApp())) { initAsStandaloneApplication(); } } return createGraphicsContextImplementation(traits); } virtual ~CocoaWindowingSystemInterface() { } private: NSString *getApplicationName(void) { NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } void createApplicationMenus(void) { NSString *appName; NSString *title; NSMenu *appleMenu; NSMenuItem *menuItem; /* Create the main menu bar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; /* Create the application menu */ appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; NSMenu* service_menu = [[NSMenu alloc] init]; NSMenuItem* service_menu_item = [[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""]; [service_menu_item setSubmenu: service_menu]; [appleMenu addItem: service_menu_item]; [NSApp setServicesMenu: service_menu]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; [menuItem release]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; [appleMenu release]; } }; } #ifdef USE_DARWIN_COCOA_IMPLEMENTATION RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy; #endif // declare C entry point for static compilation. extern "C" void graphicswindow_Cocoa(void) { osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CocoaWindowingSystemInterface()); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/Keystone.cpp0000644000175000017500000004763413151044751024146 0ustar albertoalberto/* OpenSceneGraph example, osgkeystone. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include using namespace osgViewer; Keystone::Keystone(): keystoneEditingEnabled(false), gridColour(1.0f,1.0f,1.0f,1.0f), bottom_left(-1.0,-1.0), bottom_right(1.0,-1.0), top_left(-1.0,1.0), top_right(1.0,1.0) {} Keystone::Keystone(const Keystone& rhs, const osg::CopyOp & copyop): osg::Object(rhs, copyop), keystoneEditingEnabled(rhs.keystoneEditingEnabled), gridColour(rhs.gridColour), bottom_left(rhs.bottom_left), bottom_right(rhs.bottom_right), top_left(rhs.top_left), top_right(rhs.top_right) {} void Keystone::reset() { bottom_left.set(-1.0,-1.0); bottom_right.set(1.0,-1.0); top_left.set(-1.0,1.0); top_right.set(1.0,1.0); } Keystone& Keystone::operator = (const Keystone& rhs) { if (&rhs==this) return *this; keystoneEditingEnabled = rhs.keystoneEditingEnabled; gridColour = rhs.gridColour; bottom_left = rhs.bottom_left; bottom_right = rhs.bottom_right; top_left = rhs.top_left; top_right = rhs.top_right; return *this; } void Keystone::compute3DPositions(osg::DisplaySettings* ds, osg::Vec3& tl, osg::Vec3& tr, osg::Vec3& br, osg::Vec3& bl) const { double tr_x = ((top_right-bottom_right).length()) / ((top_left-bottom_left).length()); double r_left = sqrt(tr_x); double r_right = r_left/tr_x; double tr_y = ((top_right-top_left).length()) / ((bottom_right-bottom_left).length()); double r_bottom = sqrt(tr_y); double r_top = r_bottom/tr_y; double screenDistance = ds->getScreenDistance(); double screenWidth = ds->getScreenWidth(); double screenHeight = ds->getScreenHeight(); tl = osg::Vec3(screenWidth*0.5*top_left.x(), screenHeight*0.5*top_left.y(), -screenDistance)*r_left*r_top; tr = osg::Vec3(screenWidth*0.5*top_right.x(), screenHeight*0.5*top_right.y(), -screenDistance)*r_right*r_top; br = osg::Vec3(screenWidth*0.5*bottom_right.x(), screenHeight*0.5*bottom_right.y(), -screenDistance)*r_right*r_bottom; bl = osg::Vec3(screenWidth*0.5*bottom_left.x(), screenHeight*0.5*bottom_left.y(), -screenDistance)*r_left*r_bottom; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Keystone helper functions // struct KeystoneCullCallback : public osg::Drawable::CullCallback { KeystoneCullCallback(Keystone* keystone=0):_keystone(keystone) {} KeystoneCullCallback(const KeystoneCullCallback&, const osg::CopyOp&) {} META_Object(osg,KeystoneCullCallback); /** do customized cull code, return true if drawable should be culled.*/ virtual bool cull(osg::NodeVisitor* /*nv*/, osg::Drawable* /*drawable*/, osg::RenderInfo* /*renderInfo*/) const { return _keystone.valid() ? !_keystone->getKeystoneEditingEnabled() : true; } osg::ref_ptr _keystone; }; struct KeystoneUpdateCallback : public osg::Drawable::UpdateCallback { KeystoneUpdateCallback(Keystone* keystone=0):_keystone(keystone) {} KeystoneUpdateCallback(const KeystoneUpdateCallback&, const osg::CopyOp&) {} META_Object(osg,KeystoneUpdateCallback); /** do customized update code.*/ virtual void update(osg::NodeVisitor*, osg::Drawable* drawable) { update(dynamic_cast(drawable)); } void update(osg::Geometry* geometry) { if (!geometry) return; osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); if (!vertices) return; osg::Vec2Array* texcoords = dynamic_cast(geometry->getTexCoordArray(0)); if (!texcoords) return; osg::Vec3 tl, tr, br, bl; _keystone->compute3DPositions(osg::DisplaySettings::instance().get(), tl, tr, br, bl); for(unsigned int i=0; isize(); ++i) { osg::Vec3& v = (*vertices)[i]; osg::Vec2& t = (*texcoords)[i]; v = bl * ((1.0f-t.x())*(1.0f-t.y())) + br * ((t.x())*(1.0f-t.y())) + tl * ((1.0f-t.x())*(t.y())) + tr * ((t.x())*(t.y())); } geometry->dirtyBound(); } osg::ref_ptr _keystone; }; osg::Geode* Keystone::createKeystoneDistortionMesh() { osg::ref_ptr geode = new osg::Geode; osg::ref_ptr geometry = new osg::Geometry; geode->addDrawable(geometry.get()); geometry->setUseDisplayList(false); osg::ref_ptr kuc = new KeystoneUpdateCallback(this); geometry->setUpdateCallback(kuc.get()); osg::ref_ptr colours = new osg::Vec4Array; colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); geometry->setColorArray(colours.get(), osg::Array::BIND_OVERALL); osg::ref_ptr vertices = new osg::Vec3Array; geometry->setVertexArray(vertices.get()); osg::ref_ptr texcoords = new osg::Vec2Array; geometry->setTexCoordArray(0, texcoords.get()); unsigned int numRows = 7; unsigned int numColumns = 7; unsigned int numVertices = numRows*numColumns; vertices->resize(numVertices); texcoords->resize(numVertices); for(unsigned j=0; j(i)/static_cast(numColumns-1), static_cast(j)/static_cast(numRows-1)); } } osg::ref_ptr elements = new osg::DrawElementsUShort(GL_TRIANGLES); geometry->addPrimitiveSet(elements.get()); for(unsigned j=0; jpush_back(vi+numColumns); elements->push_back(vi); elements->push_back(vi+1); elements->push_back(vi+numColumns); elements->push_back(vi+1); elements->push_back(vi+1+numColumns); } } geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); geometry->getOrCreateStateSet()->setRenderBinDetails(0, "RenderBin"); geometry->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(), osg::StateAttribute::ON|osg::StateAttribute::PROTECTED); kuc->update(geometry.get()); return geode.release(); } osg::Node* Keystone::createGrid() { osg::ref_ptr geode = new osg::Geode; osg::ref_ptr geometry = new osg::Geometry; geode->addDrawable(geometry.get()); geometry->setUseDisplayList(false); osg::ref_ptr kuc = new KeystoneUpdateCallback(this); geometry->setUpdateCallback(kuc.get()); geometry->setCullCallback(new KeystoneCullCallback(this)); osg::ref_ptr colours = new osg::Vec4Array; colours->push_back(getGridColor()); geometry->setColorArray(colours.get(), osg::Array::BIND_OVERALL); osg::ref_ptr vertices = new osg::Vec3Array; geometry->setVertexArray(vertices.get()); osg::ref_ptr texcoords = new osg::Vec2Array; geometry->setTexCoordArray(0, texcoords.get()); osg::Vec2 origin(0.0f, 0.0f); osg::Vec2 widthVector(1.0f, 0.0f); osg::Vec2 heightVector(0.0f, 1.0f); unsigned int numIntervals = 7; // border line { unsigned int vi = texcoords->size(); texcoords->push_back(origin); texcoords->push_back(origin+widthVector); texcoords->push_back(origin+widthVector+heightVector); texcoords->push_back(origin+heightVector); geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP, vi, 4)); } // cross lines { unsigned int vi = texcoords->size(); osg::Vec2 v = origin; osg::Vec2 dv = (widthVector+heightVector)/static_cast(numIntervals-1); for(unsigned int i=0; ipush_back(v); v += dv; } geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, vi, numIntervals)); vi = texcoords->size(); v = origin+heightVector; dv = (widthVector-heightVector)/static_cast(numIntervals-1); for(unsigned int i=0; ipush_back(v); v += dv; } geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, vi, numIntervals)); } // vertices lines { unsigned int vi = texcoords->size(); osg::Vec2 dv = widthVector/6.0; osg::Vec2 bv = origin+dv; osg::Vec2 tv = bv+heightVector; for(unsigned int i=0; i<5; ++i) { texcoords->push_back(bv); texcoords->push_back(tv); bv += dv; tv += dv; } geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, vi, 10)); } // horizontal lines { unsigned int vi = texcoords->size(); osg::Vec2 dv = heightVector/6.0; osg::Vec2 bv = origin+dv; osg::Vec2 tv = bv+widthVector; for(unsigned int i=0; i<5; ++i) { texcoords->push_back(bv); texcoords->push_back(tv); bv += dv; tv += dv; } geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, vi, 10)); } vertices->resize(texcoords->size()); geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); geometry->getOrCreateStateSet()->setRenderBinDetails(1, "RenderBin"); kuc->update(geometry.get()); return geode.release(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // KeystoneHandler // KeystoneHandler::KeystoneHandler(Keystone* keystone): _keystone(keystone), _defaultIncrement(0.0,0.0), _ctrlIncrement(1.0,1.0), _shiftIncrement(0.1,0.1), _keyIncrement(0.005, 0.005), _selectedRegion(NONE_SELECTED) { _startControlPoints = new Keystone; _currentControlPoints = keystone; //new Keystone; } KeystoneHandler::Region KeystoneHandler::computeRegion(const osgGA::GUIEventAdapter& ea) const { float x = ea.getXnormalized(); float y = ea.getYnormalized(); if (x<-0.33) { // left side if (y<-0.33) return BOTTOM_LEFT; else if (y<0.33) return LEFT; else return TOP_LEFT; } else if (x<0.33) { // center side if (y<-0.33) return BOTTOM; else if (y<0.33) return CENTER; else return TOP; } else { // right side if (y<-0.33) return BOTTOM_RIGHT; else if (y<0.33) return RIGHT; else return TOP_RIGHT; } return NONE_SELECTED; } void KeystoneHandler::move(Region region, const osg::Vec2d& delta) { switch(region) { case(TOP_LEFT): _currentControlPoints->getTopLeft() += delta; break; case(TOP): _currentControlPoints->getTopLeft() += delta; _currentControlPoints->getTopRight() += delta; break; case(TOP_RIGHT): _currentControlPoints->getTopRight() += delta; break; case(RIGHT): _currentControlPoints->getTopRight() += delta; _currentControlPoints->getBottomRight() += delta; break; case(BOTTOM_RIGHT): _currentControlPoints->getBottomRight() += delta; break; case(BOTTOM): _currentControlPoints->getBottomRight() += delta; _currentControlPoints->getBottomLeft() += delta; break; case(BOTTOM_LEFT): _currentControlPoints->getBottomLeft() += delta; break; case(LEFT): _currentControlPoints->getBottomLeft() += delta; _currentControlPoints->getTopLeft() += delta; break; case(CENTER): _currentControlPoints->getBottomLeft() += delta; _currentControlPoints->getTopLeft() += delta; _currentControlPoints->getBottomRight() += delta; _currentControlPoints->getTopRight() += delta; break; case(NONE_SELECTED): break; } } osg::Vec2d KeystoneHandler::incrementScale(const osgGA::GUIEventAdapter& ea) const { if (_ctrlIncrement!=osg::Vec2d(0.0,0.0) && (ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL )) return _ctrlIncrement; if (_shiftIncrement!=osg::Vec2d(0.0,0.0) && (ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT )) return _shiftIncrement; return _defaultIncrement; } bool KeystoneHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /*aa*/, osg::Object* obj, osg::NodeVisitor* /*nv*/) { osg::Camera* camera = dynamic_cast(obj); osg::Viewport* viewport = camera ? camera->getViewport() : 0; if (!viewport) return false; if (ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN && ((ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))) { if (ea.getUnmodifiedKey()=='g') { setKeystoneEditingEnabled(!getKeystoneEditingEnabled()); return true; } if (ea.getUnmodifiedKey()=='r') { _selectedRegion = NONE_SELECTED; _startControlPoints->reset(); _currentControlPoints->reset(); return true; } else if (ea.getUnmodifiedKey()=='s') { _keystone->writeToFile(); return true; } } bool haveCameraMatch = false; float x = ea.getXnormalized(); float y = ea.getYnormalized(); for(unsigned int i=0; iobject==obj) { haveCameraMatch = true; x = pd->getXnormalized(); y = pd->getYnormalized(); break; } } if (!haveCameraMatch || !getKeystoneEditingEnabled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::PUSH): { osg::Vec2d scale = incrementScale(ea); if (scale.length2()!=0.0) { _selectedRegion = computeRegion(ea); (*_startControlPoints) = (*_currentControlPoints); _startPosition.set(x,y); } else { _selectedRegion = NONE_SELECTED; } return false; } case(osgGA::GUIEventAdapter::DRAG): { if (_selectedRegion!=NONE_SELECTED) { (*_currentControlPoints) = (*_startControlPoints); osg::Vec2d currentPosition(x, y); osg::Vec2d delta(currentPosition-_startPosition); osg::Vec2d scale = incrementScale(ea); move(_selectedRegion, osg::Vec2d(delta.x()*scale.x(), delta.y()*scale.y()) ); return true; } return false; } case(osgGA::GUIEventAdapter::RELEASE): { _selectedRegion = NONE_SELECTED; return false; } case(osgGA::GUIEventAdapter::KEYDOWN): { if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up) { move(computeRegion(ea), osg::Vec2d(0.0, _keyIncrement.y()*incrementScale(ea).y()) ); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down) { move(computeRegion(ea), osg::Vec2d(0.0, -_keyIncrement.y()*incrementScale(ea).y()) ); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Left) { move(computeRegion(ea), osg::Vec2d(-_keyIncrement.x()*incrementScale(ea).x(), 0.0) ); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Right) { move(computeRegion(ea), osg::Vec2d(_keyIncrement.x()*incrementScale(ea).x(), 0.0) ); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_7 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Home) { _currentControlPoints->setTopLeft(osg::Vec2d(x, y)); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_9 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Page_Up) { _currentControlPoints->setTopRight(osg::Vec2d(x, y)); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_3 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Page_Down) { _currentControlPoints->setBottomRight(osg::Vec2d(x, y)); } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_1 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_End) { _currentControlPoints->setBottomLeft(osg::Vec2d(x, y)); } return false; } default: return false; } } bool Keystone::writeToFile() { std::string filename; if (getUserDataContainer()!=0 && getUserValue("filename", filename)) { // we don't want to write the UDC to the keystone file so take a reference to it, and set the pointer to NULL. osg::ref_ptr temp_udc = getUserDataContainer(); setUserDataContainer(0); OSG_NOTICE<<"Writing keystone to: "<getKeystoneFileNames().empty()) { for(osg::DisplaySettings::FileNames::iterator itr = ds->getKeystoneFileNames().begin(); itr != ds->getKeystoneFileNames().end(); ++itr) { const std::string& filename = *itr; osg::ref_ptr keystone = osgDB::readRefFile(filename); if (keystone.valid()) { keystone->setUserValue("filename",filename); ds->getKeystones().push_back(keystone.get()); keystonesLoaded = true; } else { OSG_NOTICE<<"Creating Keystone for filename entry: "<setUserValue("filename",filename); ds->getKeystones().push_back(keystone.get()); keystonesLoaded = true; } } } return keystonesLoaded; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/PixelBufferCocoa.mm0000644000175000017500000000756313151044751025351 0ustar albertoalberto/* * PixelBufferCocoa.cpp * OpenSceneGraph * * Created by Stephan Huber on 27.06.08. * Copyright 2008 Stephan Maximilian Huber, digital mind. All rights reserved. * */ #include #include #include #include namespace osgViewer { void PixelBufferCocoa::init() { //std::cout << "PixelBufferCocoa :: init not implemented yet " << std::endl; _valid = _initialized = true; } bool PixelBufferCocoa::realizeImplementation() { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLPixelFormatAttribute attr[32]; int i = 0; attr[i++] = NSOpenGLPFADepthSize; attr[i++] = static_cast(_traits->depth); if (_traits->doubleBuffer) { attr[i++] = NSOpenGLPFADoubleBuffer; } if (_traits->alpha) { attr[i++] = NSOpenGLPFAAlphaSize; attr[i++] = static_cast(_traits->alpha); } if (_traits->stencil) { attr[i++] = NSOpenGLPFAStencilSize; attr[i++] = static_cast(_traits->stencil); } if (_traits->sampleBuffers) { attr[i++] = NSOpenGLPFASampleBuffers; attr[i++] = static_cast(_traits->sampleBuffers); attr[i++] = NSOpenGLPFASamples; attr[i++] = static_cast(_traits->samples); } attr[i++] = NSOpenGLPFAPixelBuffer; // for pbuffer usage attr[i++] = NSOpenGLPFAAccelerated; attr[i] = static_cast(0); // create the context NSOpenGLContext* sharedContext = NULL; GraphicsHandleCocoa* graphicsHandleCocoa = dynamic_cast(_traits->sharedContext.get()); if (graphicsHandleCocoa) { sharedContext = graphicsHandleCocoa->getNSOpenGLContext(); } NSOpenGLPixelFormat* pixelformat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr ]; _context = [[NSOpenGLContext alloc] initWithFormat: pixelformat shareContext: sharedContext]; NSOpenGLPixelBuffer* pbuffer = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget: _traits->target textureInternalFormat: _traits->format textureMaxMipMapLevel: _traits->level pixelsWide: _traits->width pixelsHigh: _traits->height]; [_context setPixelBuffer: pbuffer cubeMapFace: _traits->face mipMapLevel:_traits->level currentVirtualScreen: 0]; [pool release]; _realized = (_context != nil); return _realized; } void PixelBufferCocoa::closeImplementation() { _realized = false; } /** Make this graphics context current.*/ bool PixelBufferCocoa::makeCurrentImplementation() { // OSG_INFO << "PixelBufferCocoa::makeCurrentImplementation" << std::endl; [_context makeCurrentContext]; return true; } /** Make this graphics context current with specified read context implementation. */ bool PixelBufferCocoa::makeContextCurrentImplementation(osg::GraphicsContext* readContext) { return makeCurrentImplementation(); } /** Release the graphics context.*/ bool PixelBufferCocoa::releaseContextImplementation() { // OSG_INFO << "PixelBufferCocoa::releaseContextImplementation" << std::endl; [NSOpenGLContext clearCurrentContext]; return true; } /** Bind the graphics context to associated texture implementation.*/ void PixelBufferCocoa::bindPBufferToTextureImplementation( GLenum buffer ) { std::cout << "PixelBufferCocoa :: bindPBufferToTextureImplementation not implemented yet " << std::endl; } /** Swap the front and back buffers.*/ void PixelBufferCocoa::swapBuffersImplementation() { OSG_INFO << "PixelBufferCocoa::swapBuffersImplementation" << std::endl; [_context flushBuffer]; } PixelBufferCocoa::~PixelBufferCocoa() { [_context release]; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/GraphicsWindowCarbon.cpp0000644000175000017500000011641213151044751026411 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #if defined (__APPLE__) && (!__LP64__) #include #include #include #include #include #include #include #include "DarwinUtils.h" using namespace osgViewer; using namespace osgDarwin; // Carbon-Eventhandler to handle the click in the close-widget and the resize of windows static pascal OSStatus GraphicsWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void* userData) { WindowRef window; Rect bounds; OSStatus result = eventNotHandledErr; /* report failure by default */ OSG_INFO << "GraphicsWindowEventHandler" << std::endl; GraphicsWindowCarbon* w = (GraphicsWindowCarbon*)userData; if (!w) return result; GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(window), NULL, &window); switch(GetEventClass(event)) { case kEventClassTablet: case kEventClassMouse: if (w->handleMouseEvent(event)) result = noErr; break; case kEventClassKeyboard: if (w->handleKeyboardEvent(event)) result = noErr; break; case kEventClassWindow: { switch (GetEventKind(event)) { case kEventWindowBoundsChanging: // left the code for live-resizing, but it is not used, because of window-refreshing issues... GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &bounds ); w->adaptResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top); w->requestRedraw(); result = noErr; break; case kEventWindowBoundsChanged: InvalWindowRect(window, GetWindowPortBounds(window, &bounds)); GetWindowBounds(window, kWindowContentRgn, &bounds); w->adaptResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top); result = noErr; break; case kEventWindowClose: w->requestClose(); result = noErr; break; default: break; } } default: //std::cout << "unknown: " << GetEventClass(event) << std::endl; break; } //if (result == eventNotHandledErr) // result = CallNextEventHandler (nextHandler, event); return result; } static bool s_quit_requested = false; // Application eventhandler -- listens for a quit-event static pascal OSStatus ApplicationEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) { HICommand commandStruct; OSErr err = eventNotHandledErr; GetEventParameter (inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &commandStruct); switch(commandStruct.commandID) { case kHICommandQuit: s_quit_requested = true; err = noErr; break; } return err; } // AppleEventHandler, listens to the Quit-AppleEvent static pascal OSErr QuitAppleEventHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) { s_quit_requested = true; return (noErr); } namespace osgViewer { // small helper class which maps the raw key codes to osgGA::GUIEventAdapter::Keys class CarbonKeyboardMap { public: CarbonKeyboardMap() { _keymap[53 ] = osgGA::GUIEventAdapter::KEY_Escape; _keymap[115 ] = osgGA::GUIEventAdapter::KEY_Home; _keymap[76 ] = osgGA::GUIEventAdapter::KEY_KP_Enter; _keymap[119 ] = osgGA::GUIEventAdapter::KEY_End; _keymap[36 ] = osgGA::GUIEventAdapter::KEY_Return; _keymap[116 ] = osgGA::GUIEventAdapter::KEY_Page_Up; _keymap[121 ] = osgGA::GUIEventAdapter::KEY_Page_Down; _keymap[123 ] = osgGA::GUIEventAdapter::KEY_Left; _keymap[124 ] = osgGA::GUIEventAdapter::KEY_Right; _keymap[126 ] = osgGA::GUIEventAdapter::KEY_Up; _keymap[125 ] = osgGA::GUIEventAdapter::KEY_Down; _keymap[51 ] = osgGA::GUIEventAdapter::KEY_BackSpace; _keymap[48 ] = osgGA::GUIEventAdapter::KEY_Tab; _keymap[49 ] = osgGA::GUIEventAdapter::KEY_Space; _keymap[117 ] = osgGA::GUIEventAdapter::KEY_Delete; _keymap[122 ] = osgGA::GUIEventAdapter::KEY_F1; _keymap[120 ] = osgGA::GUIEventAdapter::KEY_F2; _keymap[99 ] = osgGA::GUIEventAdapter::KEY_F3; _keymap[118 ] = osgGA::GUIEventAdapter::KEY_F4; _keymap[96 ] = osgGA::GUIEventAdapter::KEY_F5; _keymap[97 ] = osgGA::GUIEventAdapter::KEY_F6; _keymap[98 ] = osgGA::GUIEventAdapter::KEY_F7; _keymap[100 ] = osgGA::GUIEventAdapter::KEY_F8; _keymap[101 ] = osgGA::GUIEventAdapter::KEY_F9; _keymap[109 ] = osgGA::GUIEventAdapter::KEY_F10; _keymap[103 ] = osgGA::GUIEventAdapter::KEY_F11; _keymap[111 ] = osgGA::GUIEventAdapter::KEY_F12; _keymap[75 ] = osgGA::GUIEventAdapter::KEY_KP_Divide; _keymap[67 ] = osgGA::GUIEventAdapter::KEY_KP_Multiply; _keymap[78 ] = osgGA::GUIEventAdapter::KEY_KP_Subtract; _keymap[69 ] = osgGA::GUIEventAdapter::KEY_KP_Add; _keymap[89 ] = osgGA::GUIEventAdapter::KEY_KP_Home; _keymap[91 ] = osgGA::GUIEventAdapter::KEY_KP_Up; _keymap[92 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up; _keymap[86 ] = osgGA::GUIEventAdapter::KEY_KP_Left; _keymap[87 ] = osgGA::GUIEventAdapter::KEY_KP_Begin; _keymap[88 ] = osgGA::GUIEventAdapter::KEY_KP_Right; _keymap[83 ] = osgGA::GUIEventAdapter::KEY_KP_End; _keymap[84 ] = osgGA::GUIEventAdapter::KEY_KP_Down; _keymap[85 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down; _keymap[82 ] = osgGA::GUIEventAdapter::KEY_KP_Insert; _keymap[65 ] = osgGA::GUIEventAdapter::KEY_KP_Delete; } ~CarbonKeyboardMap() { } unsigned int remapKey(unsigned int key, unsigned int rawkey) { KeyMap::iterator itr = _keymap.find(rawkey); if (itr == _keymap.end()) return key; else return itr->second; } private: typedef std::map KeyMap; KeyMap _keymap; }; /** remaps a native os x keycode to a GUIEventAdapter-keycode */ static unsigned int remapCarbonKey(unsigned int key, unsigned int rawkey) { static CarbonKeyboardMap s_CarbonKeyboardMap; return s_CarbonKeyboardMap.remapKey(key,rawkey); } class CarbonWindowAdapter : public MenubarController::WindowAdapter { public: CarbonWindowAdapter(GraphicsWindowCarbon* win) : MenubarController::WindowAdapter(), _win(win) {} virtual bool valid() {return (_win.valid() && _win->valid()); } virtual void getWindowBounds(CGRect& rect) { Rect windowBounds; OSErr error = GetWindowBounds(_win->getNativeWindowRef(), kWindowStructureRgn, &windowBounds); rect.origin.x = windowBounds.left; rect.origin.y = windowBounds.top; rect.size.width = windowBounds.right - windowBounds.left; rect.size.height = windowBounds.bottom - windowBounds.top; } osgViewer::GraphicsWindow* getWindow() { return _win.get(); } private: osg::observer_ptr _win; }; void GraphicsWindowCarbon::init() { if (_initialized) return; // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); _lastModifierKeys = 0; _windowTitleHeight = 0; _closeRequested = false; _ownsWindow = false; _context = NULL; _window = NULL; _pixelFormat = PixelBufferCarbon::createPixelFormat(_traits.get()); if (!_pixelFormat) { OSG_WARN << "GraphicsWindowCarbon::init could not create a valid pixelformat" << std::endl; } _valid = (_pixelFormat != NULL); _initialized = true; // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); } bool GraphicsWindowCarbon::setWindowDecorationImplementation(bool flag) { _useWindowDecoration = flag; if (_realized) { OSErr err = noErr; Rect bounds; GetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds); if (_useWindowDecoration) { err = ChangeWindowAttributes(getNativeWindowRef(), kWindowStandardDocumentAttributes, kWindowNoTitleBarAttribute | kWindowNoShadowAttribute); SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds); } else { err = ChangeWindowAttributes(getNativeWindowRef(), kWindowNoTitleBarAttribute | kWindowNoShadowAttribute, kWindowStandardDocumentAttributes); SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds); } if (err != noErr) { OSG_WARN << "GraphicsWindowCarbon::setWindowDecoration failed with " << err << std::endl; return false; } // update titlebar-height Rect titleRect; GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect); _windowTitleHeight = abs(titleRect.bottom - titleRect.top); // sth: I don't know why I have to reattach the context to the window here, If I don't do this I get blank areas, where the titlebar was. // InvalWindowRect doesn't help here :-/ aglSetDrawable(_context, 0); aglSetDrawable(_context, GetWindowPort(_window)); MenubarController::instance()->update(); } return true; } WindowAttributes GraphicsWindowCarbon::computeWindowAttributes(bool useWindowDecoration, bool supportsResize) { WindowAttributes attr; if (useWindowDecoration) { if (supportsResize) attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute); else attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute) & ~kWindowResizableAttribute; } else { attr = kWindowNoTitleBarAttribute | kWindowNoShadowAttribute | kWindowStandardHandlerAttribute; if (supportsResize) attr |= kWindowResizableAttribute; } return attr; } void GraphicsWindowCarbon::installEventHandler() { // register window event handler to receive resize-events EventTypeSpec windEventList[] = { { kEventClassWindow, kEventWindowBoundsChanged}, { kEventClassWindow, kEventWindowClose}, {kEventClassMouse, kEventMouseDown}, {kEventClassMouse, kEventMouseUp}, {kEventClassMouse, kEventMouseMoved}, {kEventClassMouse, kEventMouseDragged}, {kEventClassMouse, kEventMouseWheelMoved}, {kEventClassMouse, 11 /* kEventMouseScroll */}, {kEventClassKeyboard, kEventRawKeyDown}, {kEventClassKeyboard, kEventRawKeyRepeat}, {kEventClassKeyboard, kEventRawKeyUp}, {kEventClassKeyboard, kEventRawKeyModifiersChanged}, {kEventClassKeyboard, kEventHotKeyPressed}, {kEventClassKeyboard, kEventHotKeyReleased}, }; InstallWindowEventHandler(_window, NewEventHandlerUPP(GraphicsWindowEventHandler), GetEventTypeCount(windEventList), windEventList, this, NULL); } bool GraphicsWindowCarbon::realizeImplementation() { if (!_initialized) init(); if (!_initialized) return false; if (!_traits) return false; OSG_INFO << "GraphicsWindowCarbon::realizeImplementation" << std::endl; setWindowDecoration(_traits->windowDecoration); useCursor(_traits->useCursor); // move the window to the right screen DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); int screenLeft = 0, screenTop = 0; if (wsi) { wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); } WindowData *windowData = ( _traits.get() && _traits->inheritedWindowData.get() ) ? static_cast(_traits->inheritedWindowData.get()) : 0; _ownsWindow = (windowData) ? (windowData->getNativeWindowRef() == NULL) : true; if (_ownsWindow) { // create the window Rect bounds = {_traits->y + screenTop, _traits->x + screenLeft, _traits->y + _traits->height + screenTop, _traits->x + _traits->width + screenLeft}; OSStatus err = 0; WindowAttributes attr = computeWindowAttributes(_useWindowDecoration, _traits->supportsResize); err = CreateNewWindow(kDocumentWindowClass, attr, &bounds, &_window); if (err) { OSG_WARN << "GraphicsWindowCarbon::realizeImplementation: failed to create window: " << err << std::endl; return false; } else { OSG_INFO << "GraphicsWindowCarbon::realizeImplementation: window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl; } } else { _window = windowData->getNativeWindowRef(); } Rect titleRect; GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect); _windowTitleHeight = abs(titleRect.bottom - titleRect.top); if ((_ownsWindow) || (windowData && windowData->installEventHandler())) installEventHandler(); // set the window title setWindowName(_traits->windowName); // create the context AGLContext sharedContextCarbon = NULL; GraphicsHandleCarbon* graphicsHandleCarbon = dynamic_cast(_traits->sharedContext.get()); if (graphicsHandleCarbon) { sharedContextCarbon = graphicsHandleCarbon->getAGLContext(); } _context = aglCreateContext (_pixelFormat, sharedContextCarbon); if (!_context) { OSG_WARN << "GraphicsWindowCarbon::realizeImplementation: failed to create context: " << aglGetError() << std::endl; return false; } if ( windowData && windowData->getAGLDrawable() ) { aglSetDrawable(_context, (AGLDrawable)*(windowData->getAGLDrawable()) ); } else { aglSetDrawable(_context, GetWindowPort(_window)); ShowWindow(_window); MenubarController::instance()->attachWindow( new CarbonWindowAdapter(this) ); } makeCurrent(); if ((_traits->useMultiThreadedOpenGLEngine) && (OpenThreads::GetNumberOfProcessors() > 1)) { // enable Multi-threaded OpenGL Execution: CGLError cgerr = kCGLNoError; CGLContextObj ctx = CGLGetCurrentContext(); #if 0 cgerr = CGLEnable( ctx, kCGLCEMPEngine); #else // the above use of kCGLCEMPEngine is not backwards compatible // so we'll use the raw value of it to keep things compiling on older // versions of OSX. cgerr = CGLEnable( ctx, static_cast (313) ); #endif if (cgerr != kCGLNoError ) { OSG_INFO << "GraphicsWindowCarbon::realizeImplementation: multi-threaded OpenGL Execution not available" << std::endl; } } InitCursor(); // enable vsync if (_traits->vsync) { GLint swap = 1; aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap); } _currentVSync = _traits->vsync; _realized = true; // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); return _realized; } bool GraphicsWindowCarbon::makeCurrentImplementation() { return (aglSetCurrentContext(_context) == GL_TRUE); } bool GraphicsWindowCarbon::releaseContextImplementation() { if (!_realized) { OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<detachWindow(this); if (_pixelFormat) { aglDestroyPixelFormat(_pixelFormat); _pixelFormat = NULL; } if (_context) { aglSetDrawable(_context, NULL); aglSetCurrentContext(NULL); aglDestroyContext(_context); _context = NULL; } if (_ownsWindow && _window) DisposeWindow(_window); _window = NULL; } void GraphicsWindowCarbon::swapBuffersImplementation() { // check for vsync change if (_traits.valid() && _traits->vsync != _currentVSync) { const bool on = _traits->vsync; GLint swap = (on ? 1 : 0); aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap); OSG_NOTICE << "GraphicsWindowCarbon: VSync=" << (on ? "on" : "off") << std::endl; _currentVSync = on; } aglSwapBuffers(_context); } void GraphicsWindowCarbon::resizedImplementation(int x, int y, int width, int height) { GraphicsContext::resizedImplementation(x, y, width, height); aglUpdateContext(_context); MenubarController::instance()->update(); getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime()); } bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) { static unsigned int lastEmulatedMouseButton = 0; // mouse down event Point wheresMyMouse; GetEventParameter (theEvent, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse); wheresMyMouse.v -= _windowTitleHeight; if (_useWindowDecoration && (wheresMyMouse.v < 0)) return false; Point wheresMyMouseGlobal; GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouseGlobal); EventMouseButton mouseButton = 0; GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton); UInt32 modifierKeys; GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys); WindowRef win; int fwres = FindWindow(wheresMyMouseGlobal, &win); // return false when Window is inactive; For enabling click-to-active on window by delegating event to default handler if (((fwres != inContent) && (fwres > 0) && (mouseButton >= 1)) || !IsWindowActive(win)) { return false; } else { UInt32 clickCount; GetEventParameter(theEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount); // swap right and middle buttons so that middle button is 2, right button is 3. if (mouseButton==3) mouseButton = 2; else if (mouseButton==2) mouseButton = 3; // check tablet pointer device and map it to a mouse button TabletProximityRec theTabletRecord; // The Tablet Proximity Record // Extract the Tablet Proximity reccord from the event. if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec, typeTabletProximityRec, NULL, sizeof(TabletProximityRec), NULL, (void *)&theTabletRecord)) { osgGA::GUIEventAdapter::TabletPointerType pointerType; switch(theTabletRecord.pointerType) { case 1: // pen pointerType = osgGA::GUIEventAdapter::PEN; break; case 2: // puck pointerType = osgGA::GUIEventAdapter::PUCK; break; case 3: // eraser pointerType = osgGA::GUIEventAdapter::ERASER; break; default: pointerType = osgGA::GUIEventAdapter::UNKNOWN; break; } getEventQueue()->penProximity(pointerType, (theTabletRecord.enterProximity != 0)); } // get tilt and rotation from the pen TabletPointRec theTabletPointRecord; if(noErr == GetEventParameter(theEvent, kEventParamTabletPointRec, typeTabletPointRec, NULL, sizeof(TabletPointRec), NULL, (void *)&theTabletPointRecord)) { int penRotation = (int)theTabletPointRecord.rotation * 9 / 575; //to get angle between 0 to 360 grad penRotation = -(((penRotation + 180) % 360) - 180) ; //for same range on all plattforms we need -180 to 180 getEventQueue()->penOrientation ( theTabletPointRecord.tiltX * 60 / 32767.0f, //multiply with 60 to get angle between -60 to 60 grad -theTabletPointRecord.tiltY * 60 / 32767.0f, //multiply with 60 to get angle between -60 to 60 grad penRotation ); } switch(GetEventKind(theEvent)) { case kEventMouseDown: { float mx = wheresMyMouse.h; float my = wheresMyMouse.v; transformMouseXY(mx, my); lastEmulatedMouseButton = 0; if (mouseButton == 1) { if( modifierKeys & cmdKey ) { mouseButton = lastEmulatedMouseButton = 3; } else if( modifierKeys & optionKey ) { mouseButton = lastEmulatedMouseButton = 2; } } if (clickCount > 1) getEventQueue()->mouseDoubleButtonPress(mx,my, mouseButton); else getEventQueue()->mouseButtonPress(mx, my, mouseButton); } break; case kEventMouseUp: { float mx = wheresMyMouse.h; float my = wheresMyMouse.v; transformMouseXY(mx, my); if (lastEmulatedMouseButton > 0) { getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton); lastEmulatedMouseButton = 0; } else { getEventQueue()->mouseButtonRelease(mx, my, mouseButton); } } break; case kEventMouseDragged: { // get pressure from the pen, only when mouse/pen is dragged TabletPointRec theTabletRecord; if(noErr == GetEventParameter(theEvent, kEventParamTabletPointRec, typeTabletPointRec, NULL, sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) { getEventQueue()->penPressure(theTabletRecord.pressure / 65535.0f); } float mx = wheresMyMouse.h; float my = wheresMyMouse.v; transformMouseXY(mx, my); getEventQueue()->mouseMotion(mx, my); } break; case kEventMouseMoved: { float mx = wheresMyMouse.h; float my = wheresMyMouse.v; transformMouseXY(mx, my); getEventQueue()->mouseMotion(mx, my); } break; // mouse with scroll-wheels case kEventMouseWheelMoved: { EventMouseWheelAxis axis; SInt32 delta; if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis )) { if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta )) { switch (axis) { case kEventMouseWheelAxisX: getEventQueue()->mouseScroll( (delta > 0) ? osgGA::GUIEventAdapter::SCROLL_RIGHT : osgGA::GUIEventAdapter::SCROLL_LEFT); break; case kEventMouseWheelAxisY: getEventQueue()->mouseScroll( (delta < 0) ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP); break; } } } } break; // new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html ) case 11: { enum { kEventParamMouseWheelSmoothVerticalDelta = 'saxy', // typeSInt32 kEventParamMouseWheelSmoothHorizontalDelta = 'saxx' // typeSInt32 }; SInt32 scroll_delta_x = 0; SInt32 scroll_delta_y = 0; OSErr err = noErr; err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y ); err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x ); if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) { getEventQueue()->mouseScroll2D( scroll_delta_x, scroll_delta_y); } } break; default: return false; } } return true; } bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent) { handleModifierKeys(theEvent); OSStatus status; UInt32 rawkey; GetEventParameter (theEvent,kEventParamKeyCode,typeUInt32, NULL,sizeof(rawkey), NULL,&rawkey); // OSG_INFO << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl; UInt32 dataSize; /* jbw check return status so that we don't allocate a huge array */ status = GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0, &dataSize, NULL ); if (status != noErr) return false; if (dataSize<=1) return false; UniChar* uniChars = new UniChar[dataSize+1]; GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars ); unsigned int keychar = remapCarbonKey(static_cast(uniChars[0]), rawkey); switch(GetEventKind(theEvent)) { case kEventRawKeyDown: case kEventRawKeyRepeat: { //OSG_INFO << "GraphicsWindowCarbon::keyPress Up" << std::endl; //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); //OSG_INFO << "GraphicsWindowCarbon::keyPress" << std::endl; getEventQueue()->keyPress(keychar); break; } case kEventRawKeyUp: { //OSG_INFO << "GraphicsWindowCarbon::keyPress" << std::endl; //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); getEventQueue()->keyRelease(keychar); break; } default: break; } delete[] uniChars; return true; } void GraphicsWindowCarbon::handleModifierKey(UInt32 modifierKey, UInt32 modifierMask, osgGA::GUIEventAdapter::KeySymbol keySymbol) { if ((modifierKey & modifierMask) && !(_lastModifierKeys & modifierMask)) { getEventQueue()->keyPress(keySymbol); } if (!(modifierKey & modifierMask) && (_lastModifierKeys & modifierMask)) { getEventQueue()->keyRelease(keySymbol); } } bool GraphicsWindowCarbon::handleModifierKeys(EventRef theEvent) { UInt32 modifierKeys; GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys); //std::cout << modifierKeys << std::endl; if (_lastModifierKeys == modifierKeys) return false; handleModifierKey(modifierKeys, shiftKey, osgGA::GUIEventAdapter::KEY_Shift_L); handleModifierKey(modifierKeys, controlKey, osgGA::GUIEventAdapter::KEY_Control_L); handleModifierKey(modifierKeys, optionKey, osgGA::GUIEventAdapter::KEY_Alt_L); handleModifierKey(modifierKeys, cmdKey, osgGA::GUIEventAdapter::KEY_Super_L); // Caps lock needs some special handling, i did not find a way to get informed when the caps-lock-key gets released if ((modifierKeys & alphaLock) && !(_lastModifierKeys & alphaLock)) { getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_Caps_Lock); getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_Caps_Lock); } if (!(modifierKeys & alphaLock) && (_lastModifierKeys & alphaLock)) { getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_Caps_Lock); getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_Caps_Lock); } _lastModifierKeys = modifierKeys; return true; } bool GraphicsWindowCarbon::checkEvents() { if (!_realized) return false; EventRef theEvent; EventTargetRef theTarget = GetEventDispatcherTarget(); while (ReceiveNextEvent(0, NULL, 0,true, &theEvent)== noErr) { switch(GetEventClass(theEvent)) { case kEventClassMouse: { // handle the menubar Point wheresMyMouse; GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse); EventMouseButton mouseButton = 0; GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton); WindowRef win; int fwres = FindWindow(wheresMyMouse, &win); if ((fwres == inMenuBar) && (mouseButton >= 1)) { MenuSelect(wheresMyMouse); HiliteMenu(0); return !(getEventQueue()->empty()); } break; } case kEventClassApplication: switch (GetEventKind(theEvent)) { case kEventAppQuit: getEventQueue()->quitApplication(); break; } break; case kEventClassAppleEvent: { EventRecord eventRecord; ConvertEventRefToEventRecord(theEvent, &eventRecord); AEProcessAppleEvent(&eventRecord); return; } break; } SendEventToEventTarget (theEvent, theTarget); ReleaseEvent(theEvent); } if (_closeRequested) getEventQueue()->closeWindow(); if (s_quit_requested) { getEventQueue()->quitApplication(); s_quit_requested = false; } return !(getEventQueue()->empty()); } bool GraphicsWindowCarbon::setWindowRectangleImplementation(int x, int y, int width, int height) { int screenLeft(0), screenTop(0); DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi) { wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); } Rect bounds = {y + screenTop, x + screenLeft, y + height + screenTop, x + width + screenLeft}; SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds); aglUpdateContext(_context); MenubarController::instance()->update(); return true; } void GraphicsWindowCarbon::adaptResize(int x, int y, int w, int h) { DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); int screenLeft(0), screenTop(0); if (wsi) { // get the screen containing the window unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h); // update traits _traits->screenNum = screenNdx; // get top left of screen wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); } resized(x-screenLeft,y-screenTop,w,h); } void GraphicsWindowCarbon::grabFocus() { SelectWindow(_window); } void GraphicsWindowCarbon::grabFocusIfPointerInWindow() { // TODO: implement OSG_NOTIFY(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow: not implemented" << std::endl; } void GraphicsWindowCarbon::useCursor(bool cursorOn) { if (_traits.valid()) _traits->useCursor = cursorOn; DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi == NULL) { OSG_WARN << "GraphicsWindowCarbon::useCursor: could not get OSXCarbonWindowingSystemInterface" << std::endl; return; } CGDirectDisplayID displayId = wsi->getDisplayID((*_traits)); CGDisplayErr err = (cursorOn ? CGDisplayShowCursor(displayId) : CGDisplayHideCursor(displayId)); if (err != kCGErrorSuccess) { OSG_WARN << "GraphicsWindowCarbon::useCursor: failed with " << err << std::endl; } } // FIXME: need to implement all cursor types // FIXME: I used deprecated functions, but don't know if there are any substitutable newer functions... void GraphicsWindowCarbon::setCursor(MouseCursor mouseCursor) { if (_currentCursor == mouseCursor) return; UInt32 cursor; switch (mouseCursor) { case NoCursor: HideCursor(); _currentCursor = mouseCursor; return; case RightArrowCursor: cursor = kThemeArrowCursor; break; case CrosshairCursor: cursor = kThemeCrossCursor; break; case TextCursor: cursor = kThemeIBeamCursor; break; case UpDownCursor: cursor = kThemeResizeUpDownCursor; break; case LeftRightCursor: cursor = kThemeResizeLeftRightCursor; break; default: cursor = kThemeArrowCursor; OSG_WARN << "GraphicsWindowCarbon::setCursor doesn't implement cursor: type = " << mouseCursor << std::endl; } _currentCursor = mouseCursor; SetThemeCursor(cursor); ShowCursor(); } void GraphicsWindowCarbon::setSyncToVBlank(bool on) { if (_traits.valid()) { _traits->vsync = on; } } void GraphicsWindowCarbon::setWindowName (const std::string& name) { _traits->windowName = name; if (!_traits->windowName.empty()) { CFStringRef windowtitle = CFStringCreateWithBytes( kCFAllocatorDefault, (const UInt8*)(_traits->windowName.c_str()), _traits->windowName.length(),kCFStringEncodingUTF8, false ); SetWindowTitleWithCFString( _window, windowtitle ); CFRelease(windowtitle); } } void GraphicsWindowCarbon::requestWarpPointer(float x,float y) { if (!_realized) { OSG_INFO<<"GraphicsWindowCarbon::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi == NULL) { OSG_WARN << "GraphicsWindowCarbon::useCursor: could not get OSXCarbonWindowingSystemInterface" << std::endl; return; } CGDirectDisplayID displayId = wsi->getDisplayID((*_traits)); CGPoint point; point.x = x + _traits->x; point.y = y + _traits->y; CGDisplayMoveCursorToPoint(displayId, point); getEventQueue()->mouseWarped(x,y); } void GraphicsWindowCarbon::transformMouseXY(float& x, float& y) { if (getEventQueue()->getUseFixedMouseInputRange()) { osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState(); x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width); y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height); } } class CarbonWindowingSystemInterface : public DarwinWindowingSystemInterface { public: CarbonWindowingSystemInterface() : DarwinWindowingSystemInterface() { } virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) { _init(); return createGraphicsContextImplementation(traits); } virtual void _init() { if (_initialized) return; DarwinWindowingSystemInterface::_init(); // register application event handler and AppleEventHandler to get quit-events: static const EventTypeSpec menueventSpec = {kEventClassCommand, kEventCommandProcess}; OSErr status = InstallEventHandler(GetApplicationEventTarget(), NewEventHandlerUPP(ApplicationEventHandler), 1, &menueventSpec, 0, NULL); status = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false); } }; } #ifdef USE_DARWIN_CARBON_IMPLEMENTATION RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy; #endif // declare C entry point for static compilation. extern "C" void graphicswindow_Carbon(void) { osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CarbonWindowingSystemInterface()); } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/CompositeViewer.cpp0000644000175000017500000013516213151044751025463 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include using namespace osgViewer; CompositeViewer::CompositeViewer() { constructorInit(); } CompositeViewer::CompositeViewer(const CompositeViewer& cv,const osg::CopyOp& /*copyop*/): osg::Object(true), ViewerBase(cv) { constructorInit(); } CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments) { constructorInit(); arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select SingleThreaded threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select CullDrawThreadPerContext threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select DrawThreadPerContext threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select CullThreadPerCameraDrawThreadPerContext threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--run-on-demand","Set the run methods frame rate management to only rendering frames when required."); arguments.getApplicationUsage()->addCommandLineOption("--run-continuous","Set the run methods frame rate management to rendering frames continuously."); arguments.getApplicationUsage()->addCommandLineOption("--run-max-frame-rate","Set the run methods maximum permissible frame rate, 0.0 is default and switching off frame rate capping."); std::string filename; bool readConfig = false; while (arguments.read("-c",filename)) { readConfig = readConfiguration(filename) || readConfig; } while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded); while (arguments.read("--CullDrawThreadPerContext")) setThreadingModel(CullDrawThreadPerContext); while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext); while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) setThreadingModel(CullThreadPerCameraDrawThreadPerContext); while(arguments.read("--run-on-demand")) { setRunFrameScheme(ON_DEMAND); } while(arguments.read("--run-continuous")) { setRunFrameScheme(CONTINUOUS); } double runMaxFrameRate; while(arguments.read("--run-max-frame-rate", runMaxFrameRate)) { setRunMaxFrameRate(runMaxFrameRate); } osg::DisplaySettings::instance()->readCommandLine(arguments); osgDB::readCommandLine(arguments); } void CompositeViewer::constructorInit() { _endBarrierPosition = AfterSwapBuffers; _startTick = 0; // make sure View is safe to reference multi-threaded. setThreadSafeRefUnref(true); _frameStamp = new osg::FrameStamp; _frameStamp->setFrameNumber(0); _frameStamp->setReferenceTime(0); _frameStamp->setSimulationTime(0); _eventVisitor = new osgGA::EventVisitor; _eventVisitor->setFrameStamp(_frameStamp.get()); _updateVisitor = new osgUtil::UpdateVisitor; _updateVisitor->setFrameStamp(_frameStamp.get()); setViewerStats(new osg::Stats("CompsiteViewer")); } CompositeViewer::~CompositeViewer() { OSG_INFO<<"CompositeViewer::~CompositeViewer()"<getDatabasePager()) { scene->getDatabasePager()->cancel(); scene->setDatabasePager(0); } } Contexts contexts; getContexts(contexts); // clear out all the previously assigned operations for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { (*citr)->close(); } OSG_INFO<<"finished CompositeViewer::~CompositeViewer()"< obj = osgDB::readRefObjectFile(filename); osgViewer::View * view = dynamic_cast(obj.get()); if (view) { addView(view); return true; } return false; } void CompositeViewer::addView(osgViewer::View* view) { if (!view) return; bool alreadyRealized = isRealized(); bool threadsWereRunning = _threadsRunning; if (threadsWereRunning) stopThreading(); _views.push_back(view); view->_viewerBase = this; if (view->getSceneData()) { // make sure that existing scene graph objects are allocated with thread safe ref/unref if (getThreadingModel()!=ViewerBase::SingleThreaded) { view->getSceneData()->setThreadSafeRefUnref(true); } // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it. view->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts()); } view->setFrameStamp(_frameStamp.get()); if (alreadyRealized) { Contexts contexts; if (view->getCamera()->getGraphicsContext()) { contexts.push_back(view->getCamera()->getGraphicsContext()); } for(unsigned int i=0; igetNumSlaves(); ++i) { if (view->getSlave(i)._camera->getGraphicsContext()) { contexts.push_back(view->getSlave(i)._camera->getGraphicsContext()); } } for(Contexts::iterator itr = contexts.begin(); itr != contexts.end(); ++itr) { if (!((*itr)->isRealized())) { (*itr)->realize(); } } } if (threadsWereRunning) startThreading(); } void CompositeViewer::removeView(osgViewer::View* view) { for(RefViews::iterator itr = _views.begin(); itr != _views.end(); ++itr) { if (*itr == view) { bool threadsWereRunning = _threadsRunning; if (threadsWereRunning) stopThreading(); view->_viewerBase = 0; _views.erase(itr); if (threadsWereRunning) startThreading(); return; } } } bool CompositeViewer::isRealized() const { Contexts contexts; const_cast(this)->getContexts(contexts); unsigned int numRealizedWindows = 0; // clear out all the previously assigned operations for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { if ((*citr)->isRealized()) ++numRealizedWindows; } return numRealizedWindows > 0; } bool CompositeViewer::checkNeedToDoFrame() { if (_requestRedraw) return true; if (_requestContinousUpdate) return true; for(RefViews::iterator itr = _views.begin(); itr != _views.end(); ++itr) { osgViewer::View* view = itr->get(); if (view) { // check if the database pager needs to update the scene if (view->getDatabasePager()->requiresUpdateSceneGraph() || view->getDatabasePager()->getRequestsInProgress()) return true; // check if there are camera update callbacks if (view->getCamera()->getUpdateCallback()) return true; // check if there are node update callbacks if (view->getSceneData() != 0) { if (view->getSceneData()->getUpdateCallback() || (view->getSceneData()->getNumChildrenRequiringUpdateTraversal()>0) ) return true; } } } // check if events are available and need processing if (checkEvents()) return true; if (_requestRedraw) return true; if (_requestContinousUpdate) return true; return false; } bool CompositeViewer::checkEvents() { for(RefViews::iterator itr = _views.begin(); itr != _views.end(); ++itr) { osgViewer::View* view = itr->get(); if (view) { // check events from any attached sources for(View::Devices::iterator eitr = view->getDevices().begin(); eitr != view->getDevices().end(); ++eitr) { osgGA::Device* es = eitr->get(); if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS) { if (es->checkEvents()) return true; } } } } // get events from all windows attached to Viewer. Windows windows; getWindows(windows); for(Windows::iterator witr = windows.begin(); witr != windows.end(); ++witr) { if ((*witr)->checkEvents()) return true; } return false; } int CompositeViewer::run() { for(RefViews::iterator itr = _views.begin(); itr != _views.end(); ++itr) { osgViewer::View* view = itr->get(); if ((view->getCameraManipulator()==0) && view->getCamera()->getAllowEventFocus()) { view->setCameraManipulator(new osgGA::TrackballManipulator()); } } setReleaseContextAtEndOfFrameHint(false); return ViewerBase::run(); } void CompositeViewer::setStartTick(osg::Timer_t tick) { _startTick = tick; for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { (*vitr)->setStartTick(tick); } Contexts contexts; getContexts(contexts,false); for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->getEventQueue()->setStartTick(_startTick); } } } void CompositeViewer::setReferenceTime(double time) { osg::Timer_t tick = osg::Timer::instance()->tick(); double currentTime = osg::Timer::instance()->delta_s(_startTick, tick); double delta_ticks = (time-currentTime)/(osg::Timer::instance()->getSecondsPerTick()); if (delta_ticks>=0) tick += osg::Timer_t(delta_ticks); else tick -= osg::Timer_t(-delta_ticks); // assign the new start tick setStartTick(tick); } void CompositeViewer::viewerInit() { OSG_INFO<<"CompositeViewer::init()"<init(); } } void CompositeViewer::getContexts(Contexts& contexts, bool onlyValid) { typedef std::set ContextSet; ContextSet contextSet; contexts.clear(); for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { osgViewer::View* view = vitr->get(); osg::GraphicsContext* gc = view->getCamera() ? view->getCamera()->getGraphicsContext() : 0; if (gc && (gc->valid() || !onlyValid)) { if (contextSet.count(gc)==0) { contextSet.insert(gc); contexts.push_back(gc); } } for(unsigned int i=0; igetNumSlaves(); ++i) { View::Slave& slave = view->getSlave(i); osg::GraphicsContext* sgc = slave._camera.valid() ? slave._camera->getGraphicsContext() : 0; if (sgc && (sgc->valid() || !onlyValid)) { if (contextSet.count(sgc)==0) { contextSet.insert(sgc); contexts.push_back(sgc); } } } } } void CompositeViewer::getCameras(Cameras& cameras, bool onlyActive) { cameras.clear(); for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { View* view = vitr->get(); if (view->getCamera() && (!onlyActive || (view->getCamera()->getGraphicsContext() && view->getCamera()->getGraphicsContext()->valid())) ) cameras.push_back(view->getCamera()); for(View::Slaves::iterator itr = view->_slaves.begin(); itr != view->_slaves.end(); ++itr) { if (itr->_camera.valid() && (!onlyActive || (itr->_camera->getGraphicsContext() && itr->_camera->getGraphicsContext()->valid())) ) cameras.push_back(itr->_camera.get()); } } } void CompositeViewer::getScenes(Scenes& scenes, bool onlyValid) { scenes.clear(); typedef std::set SceneSet; SceneSet sceneSet; for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { osgViewer::View* view = vitr->get(); if (view->getScene() && (!onlyValid || view->getScene()->getSceneData())) { if (sceneSet.count(view->getScene())==0) { sceneSet.insert(view->getScene()); scenes.push_back(view->getScene()); } } } } void CompositeViewer::getViews(Views& views, bool /*onlyValid*/) { views.clear(); for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { views.push_back(vitr->get()); } } void CompositeViewer::getAllThreads(Threads& threads, bool onlyActive) { threads.clear(); OperationThreads operationThreads; getOperationThreads(operationThreads); for(OperationThreads::iterator itr = operationThreads.begin(); itr != operationThreads.end(); ++itr) { threads.push_back(*itr); } Scenes scenes; getScenes(scenes); for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; osgDB::DatabasePager* dp = scene->getDatabasePager(); if (dp) { for(unsigned int i=0; igetNumDatabaseThreads(); ++i) { osgDB::DatabasePager::DatabaseThread* dt = dp->getDatabaseThread(i); if (!onlyActive || dt->isRunning()) { threads.push_back(dt); } } } } } void CompositeViewer::getOperationThreads(OperationThreads& threads, bool onlyActive) { threads.clear(); Contexts contexts; getContexts(contexts); for(Contexts::iterator gcitr = contexts.begin(); gcitr != contexts.end(); ++gcitr) { osg::GraphicsContext* gc = *gcitr; if (gc->getGraphicsThread() && (!onlyActive || gc->getGraphicsThread()->isRunning()) ) { threads.push_back(gc->getGraphicsThread()); } } Cameras cameras; getCameras(cameras); for(Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { osg::Camera* camera = *citr; if (camera->getCameraThread() && (!onlyActive || camera->getCameraThread()->isRunning()) ) { threads.push_back(camera->getCameraThread()); } } } void CompositeViewer::realize() { //OSG_INFO<<"CompositeViewer::realize()"<setUpViewAcrossAllScreens(); getContexts(contexts); } if (contexts.empty()) { OSG_NOTICE<<"CompositeViewer::realize() - failed to set up any windows"<getDisplaySettings()==0) wsi->setDisplaySettings(ds); unsigned int maxTexturePoolSize = ds->getMaxTexturePoolSize(); unsigned int maxBufferObjectPoolSize = ds->getMaxBufferObjectPoolSize(); for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osg::GraphicsContext* gc = *citr; if (ds->getSyncSwapBuffers()) gc->setSwapCallback(new osg::SyncSwapBuffersCallback); // set the pool sizes, 0 the default will result in no GL object pools. gc->getState()->setMaxTexturePoolSize(maxTexturePoolSize); gc->getState()->setMaxBufferObjectPoolSize(maxBufferObjectPoolSize); gc->realize(); if (_realizeOperation.valid() && gc->valid()) { gc->makeCurrent(); (*_realizeOperation)(gc); gc->releaseContext(); } } // attach contexts to _incrementalCompileOperation if attached. if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); bool grabFocus = true; if (grabFocus) { for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->grabFocusIfPointerInWindow(); } } } // initialize the global timer to be relative to the current time. osg::Timer::instance()->setStartTick(); // pass on the start tick to all the associated eventqueues setStartTick(osg::Timer::instance()->getStartTick()); // configure threading. setUpThreading(); if (osg::DisplaySettings::instance()->getCompileContextsHint()) { int numProcessors = OpenThreads::GetNumberOfProcessors(); int processNum = 0; for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i) { osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i); if (gc) { gc->createGraphicsThread(); gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors); gc->getGraphicsThread()->startThread(); ++processNum; } } } } void CompositeViewer::advance(double simulationTime) { if (_done) return; double previousReferenceTime = _frameStamp->getReferenceTime(); unsigned int previousFrameNumber = _frameStamp->getFrameNumber(); _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1); _frameStamp->setReferenceTime( osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()) ); if (simulationTime==USE_REFERENCE_TIME) { _frameStamp->setSimulationTime(_frameStamp->getReferenceTime()); } else { _frameStamp->setSimulationTime(simulationTime); } if (getViewerStats() && getViewerStats()->collectStats("frame_rate")) { // update previous frame stats double deltaFrameTime = _frameStamp->getReferenceTime() - previousReferenceTime; getViewerStats()->setAttribute(previousFrameNumber, "Frame duration", deltaFrameTime); getViewerStats()->setAttribute(previousFrameNumber, "Frame rate", 1.0/deltaFrameTime); // update current frames stats getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Reference time", _frameStamp->getReferenceTime()); } } void CompositeViewer::setCameraWithFocus(osg::Camera* camera) { _cameraWithFocus = camera; if (camera) { for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { View* view = vitr->get(); if (view->containsCamera(camera)) { _viewWithFocus = view; return; } } } _viewWithFocus = 0; } void CompositeViewer::generateSlavePointerData(osg::Camera* camera, osgGA::GUIEventAdapter& event) { osgViewer::GraphicsWindow* gw = dynamic_cast(event.getGraphicsContext()); if (!gw) return; // What type of Camera is it? // 1) Master Camera : do nothin extra // 2) Slave Camera, Relative RF, Same scene graph as master : transform coords into Master Camera and add to PointerData list // 3) Slave Camera, Relative RF, Different scene graph from master : do nothing extra? // 4) Slave Camera, Absolute RF, Same scene graph as master : do nothing extra? // 5) Slave Camera, Absolute RF, Different scene graph : do nothing extra? // 6) Slave Camera, Absolute RF, Different scene graph but a distortion correction subgraph depending upon RTT Camera (slave or master) // : project ray into RTT Camera's clip space, and RTT Camera's is Relative RF and sharing same scene graph as master then transform coords. // if camera isn't the master it must be a slave and could need reprojecting. osgViewer::View* view = dynamic_cast(camera->getView()); if (!view) return; osg::Camera* view_masterCamera = view->getCamera(); if (camera!=view_masterCamera) { float x = event.getX(); float y = event.getY(); bool invert_y = event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; double master_min_x = -1.0; double master_max_x = 1.0; double master_min_y = -1.0; double master_max_y = 1.0; osg::Matrix masterCameraVPW = view_masterCamera->getViewMatrix() * view_masterCamera->getProjectionMatrix(); if (view_masterCamera->getViewport()) { osg::Viewport* viewport = view_masterCamera->getViewport(); master_min_x = viewport->x(); master_min_y = viewport->y(); master_max_x = viewport->x()+viewport->width(); master_max_y = viewport->y()+viewport->height(); masterCameraVPW *= viewport->computeWindowMatrix(); } // slave Camera tahnks to sharing the same View osg::View::Slave* slave = view ? view->findSlaveForCamera(camera) : 0; if (slave) { if (camera->getReferenceFrame()==osg::Camera::RELATIVE_RF && slave->_useMastersSceneData) { osg::Viewport* viewport = camera->getViewport(); osg::Matrix localCameraVPW = camera->getViewMatrix() * camera->getProjectionMatrix(); if (viewport) localCameraVPW *= viewport->computeWindowMatrix(); osg::Matrix matrix( osg::Matrix::inverse(localCameraVPW) * masterCameraVPW ); osg::Vec3d new_coord = osg::Vec3d(x,y,0.0) * matrix; //OSG_NOTICE<<" pointer event new_coord.x()="<second._texture.get()<<", "<second._face<(event.getGraphicsContext()); if (!gw) return; float x = event.getX(); float y = event.getY(); bool invert_y = event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; event.addPointerData(new osgGA::PointerData(gw, x, 0, gw->getTraits()->width, y, 0, gw->getTraits()->height)); event.setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); typedef std::vector CameraVector; CameraVector activeCameras; osg::GraphicsContext::Cameras& cameras = gw->getCameras(); for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { osg::Camera* camera = *citr; if (camera->getAllowEventFocus() && camera->getRenderTargetImplementation()==osg::Camera::FRAME_BUFFER) { osg::Viewport* viewport = camera ? camera->getViewport() : 0; if (viewport && x >= viewport->x() && y >= viewport->y() && x <= (viewport->x()+viewport->width()) && y <= (viewport->y()+viewport->height()) ) { activeCameras.push_back(camera); } } } std::sort(activeCameras.begin(), activeCameras.end(), osg::CameraRenderOrderSortOp()); osg::Camera* camera = activeCameras.empty() ? 0 : activeCameras.back(); if (camera) { osg::Viewport* viewport = camera ? camera->getViewport() : 0; event.addPointerData(new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0, (y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0)); osgViewer::View* view = dynamic_cast(camera->getView()); osg::Camera* view_masterCamera = view ? view->getCamera() : 0; // if camera isn't the master it must be a slave and could need reprojecting. if (view && camera!=view_masterCamera) { generateSlavePointerData(camera, event); } } } void CompositeViewer::reprojectPointerData(osgGA::GUIEventAdapter& source_event, osgGA::GUIEventAdapter& dest_event) { osgViewer::GraphicsWindow* gw = dynamic_cast(dest_event.getGraphicsContext()); if (!gw) return; float x = dest_event.getX(); float y = dest_event.getY(); bool invert_y = dest_event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; dest_event.addPointerData(new osgGA::PointerData(gw, x, 0, gw->getTraits()->width, y, 0, gw->getTraits()->height)); dest_event.setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); osg::Camera* camera = (source_event.getNumPointerData()>=2) ? dynamic_cast(source_event.getPointerData(1)->object.get()) : 0; osg::Viewport* viewport = camera ? camera->getViewport() : 0; if (!viewport) return; dest_event.addPointerData(new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0, (y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0)); osgViewer::View* view = dynamic_cast(camera->getView()); osg::Camera* view_masterCamera = view ? view->getCamera() : 0; // if camera isn't the master it must be a slave and could need reprojecting. if (view && camera!=view_masterCamera) { generateSlavePointerData(camera, dest_event); } } struct SortEvents { bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) const { return lhs->getTime() < rhs->getTime(); } }; void CompositeViewer::eventTraversal() { if (_done) return; if (_views.empty()) return; double cutOffTime = _frameStamp->getReferenceTime(); double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // need to copy events from the GraphicsWindow's into local EventQueue for each view; typedef std::map ViewEventsMap; ViewEventsMap viewEventsMap; Contexts contexts; getContexts(contexts); // set done if there are no windows checkWindowStatus(contexts); if (_done) return; osgGA::EventQueue::Events all_events; for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->checkEvents(); osgGA::EventQueue::Events gw_events; gw->getEventQueue()->takeEvents(gw_events, cutOffTime); for(osgGA::EventQueue::Events::iterator itr = gw_events.begin(); itr != gw_events.end(); ++itr) { osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter(); if (ea) ea->setGraphicsContext(gw); } all_events.insert(all_events.end(), gw_events.begin(), gw_events.end()); } } // sort all the events in time order so we can make sure we pass them all on in the correct order. all_events.sort(SortEvents()); // pass on pointer data onto non mouse events to keep the position data usable by all recipients of all events. for(osgGA::EventQueue::Events::iterator itr = all_events.begin(); itr != all_events.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::PUSH): case(osgGA::GUIEventAdapter::RELEASE): case(osgGA::GUIEventAdapter::DOUBLECLICK): case(osgGA::GUIEventAdapter::MOVE): case(osgGA::GUIEventAdapter::DRAG): { if ((event->getEventType()!=osgGA::GUIEventAdapter::DRAG && event->getEventType()!=osgGA::GUIEventAdapter::RELEASE) || !_previousEvent || _previousEvent->getGraphicsContext()!=event->getGraphicsContext() || _previousEvent->getNumPointerData()<2) { generatePointerData(*event); } else { reprojectPointerData(*_previousEvent, *event); } _previousEvent = event; break; } default: if (_previousEvent.valid()) event->copyPointerDataFrom(*_previousEvent); break; } osgGA::PointerData* pd = event->getNumPointerData()>0 ? event->getPointerData(event->getNumPointerData()-1) : 0; osg::Camera* camera = pd ? dynamic_cast(pd->object.get()) : 0; osgViewer::View* view = camera ? dynamic_cast(camera->getView()) : 0; if (!view) { if (_viewWithFocus.valid()) { // OSG_NOTICE<<"Falling back to using _viewWithFocus"<getEventQueue()->getCurrentEventState(); eventState->copyPointerDataFrom(*event); } _previousEvent = event; } // handle any close windows for(osgGA::EventQueue::Events::iterator itr = all_events.begin(); itr != all_events.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::CLOSE_WINDOW): { bool wasThreading = areThreadsRunning(); if (wasThreading) stopThreading(); if (event->getGraphicsContext()) { event->getGraphicsContext()->close(); } if (wasThreading) startThreading(); break; } default: break; } } for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { View* view = vitr->get(); // get events from user Devices attached to Viewer. for(osgViewer::View::Devices::iterator eitr = view->getDevices().begin(); eitr != view->getDevices().end(); ++eitr) { osgGA::Device* es = eitr->get(); if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS) es->checkEvents(); // open question, will we need to reproject mouse coordinates into current view's coordinate frame as is down for GraphicsWindow provided events? // for now assume now and just get the events directly without any reprojection. es->getEventQueue()->takeEvents(viewEventsMap[view], cutOffTime); } // create a frame event for the new frame. { osg::ref_ptr event = view->getEventQueue()->frame( getFrameStamp()->getReferenceTime() ); if (!_previousEvent || _previousEvent->getNumPointerData()<2) { generatePointerData(*event); } else { reprojectPointerData(*_previousEvent, *event); } } view->getEventQueue()->takeEvents(viewEventsMap[view], cutOffTime); } if ((_keyEventSetsDone!=0) || _quitEventSetsDone) { for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); veitr != viewEventsMap.end(); ++veitr) { for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); itr != veitr->second.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; // ignore event if it's already been handled. if (event->getHandled()) continue; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): if (_keyEventSetsDone && event->getKey()==_keyEventSetsDone) _done = true; break; case(osgGA::GUIEventAdapter::QUIT_APPLICATION): if (_quitEventSetsDone) _done = true; break; default: break; } } } } if (_done) return; if (_eventVisitor.valid()) { _eventVisitor->setFrameStamp(getFrameStamp()); _eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); veitr != viewEventsMap.end(); ++veitr) { View* view = veitr->first; _eventVisitor->setActionAdapter(view); if (view && view->getSceneData()) { for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); itr != veitr->second.end(); ++itr) { osgGA::Event* event = itr->get(); _eventVisitor->reset(); _eventVisitor->addEvent( event ); view->getSceneData()->accept(*_eventVisitor); // Do EventTraversal for slaves with their own subgraph for(unsigned int i=0; igetNumSlaves(); ++i) { osg::View::Slave& slave = view->getSlave(i); osg::Camera* camera = slave._camera.get(); if(camera && !slave._useMastersSceneData) { camera->accept(*_eventVisitor); } } // call any camera event callbacks, but only traverse that callback, don't traverse its subgraph // leave that to the scene update traversal. osg::NodeVisitor::TraversalMode tm = _eventVisitor->getTraversalMode(); _eventVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE); if (view->getCamera() && view->getCamera()->getEventCallback()) view->getCamera()->accept(*_eventVisitor); for(unsigned int i=0; igetNumSlaves(); ++i) { osg::View::Slave& slave = view->getSlave(i); osg::Camera* camera = view->getSlave(i)._camera.get(); if (camera && slave._useMastersSceneData && camera->getEventCallback()) { camera->accept(*_eventVisitor); } } _eventVisitor->setTraversalMode(tm); } } } } for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); veitr != viewEventsMap.end(); ++veitr) { View* view = veitr->first; _eventVisitor->setActionAdapter(view); for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); itr != veitr->second.end(); ++itr) { osgGA::Event* event = itr->get(); for(View::EventHandlers::iterator hitr = view->getEventHandlers().begin(); hitr != view->getEventHandlers().end(); ++hitr) { (*hitr)->handle( event, view, _eventVisitor.get()); } } } for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); veitr != viewEventsMap.end(); ++veitr) { View* view = veitr->first; _eventVisitor->setActionAdapter(view); for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); itr != veitr->second.end(); ++itr) { osgGA::Event* event = itr->get(); if (view->getCameraManipulator()) { view->getCameraManipulator()->handle( event, view, _eventVisitor.get()); } } } if (getViewerStats() && getViewerStats()->collectStats("event")) { double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // update current frames stats getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal begin time", beginEventTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal end time", endEventTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal time taken", endEventTraversal-beginEventTraversal); } } void CompositeViewer::updateTraversal() { if (_done) return; double beginUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); _updateVisitor->reset(); _updateVisitor->setFrameStamp(getFrameStamp()); _updateVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); Scenes scenes; getScenes(scenes); for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; scene->updateSceneGraph(*_updateVisitor); } // if we have a shared state manager prune any unused entries if (osgDB::Registry::instance()->getSharedStateManager()) osgDB::Registry::instance()->getSharedStateManager()->prune(); // update the Registry object cache. osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(*getFrameStamp()); osgDB::Registry::instance()->removeExpiredObjectsInCache(*getFrameStamp()); if (_incrementalCompileOperation.valid()) { // merge subgraphs that have been compiled by the incremental compiler operation. _incrementalCompileOperation->mergeCompiledSubgraphs(getFrameStamp()); } if (_updateOperations.valid()) { _updateOperations->runOperations(this); } for(RefViews::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { View* view = vitr->get(); { // Do UpdateTraversal for slaves with their own subgraph for(unsigned int i=0; igetNumSlaves(); ++i) { osg::View::Slave& slave = view->getSlave(i); osg::Camera* camera = slave._camera.get(); if(camera && !slave._useMastersSceneData) { camera->accept(*_updateVisitor); } } // call any camera update callbacks, but only traverse that callback, don't traverse its subgraph // leave that to the scene update traversal. osg::NodeVisitor::TraversalMode tm = _updateVisitor->getTraversalMode(); _updateVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE); if (view->getCamera() && view->getCamera()->getUpdateCallback()) view->getCamera()->accept(*_updateVisitor); for(unsigned int i=0; igetNumSlaves(); ++i) { osg::View::Slave& slave = view->getSlave(i); osg::Camera* camera = slave._camera.get(); if (camera && slave._useMastersSceneData && camera->getUpdateCallback()) { camera->accept(*_updateVisitor); } } _updateVisitor->setTraversalMode(tm); } if (view->getCameraManipulator()) { view->setFusionDistance( view->getCameraManipulator()->getFusionDistanceMode(), view->getCameraManipulator()->getFusionDistanceValue() ); view->getCameraManipulator()->updateCamera(*(view->getCamera())); } view->updateSlaves(); } if (getViewerStats() && getViewerStats()->collectStats("update")) { double endUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // update current frames stats getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal begin time", beginUpdateTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal end time", endUpdateTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal time taken", endUpdateTraversal-beginUpdateTraversal); } } double CompositeViewer::elapsedTime() { return osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); } void CompositeViewer::getUsage(osg::ApplicationUsage& usage) const { for(RefViews::const_iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { const View* view = vitr->get(); if (view->getCameraManipulator()) { view->getCameraManipulator()->getUsage(usage); } for(View::EventHandlers::const_iterator hitr = view->_eventHandlers.begin(); hitr != view->_eventHandlers.end(); ++hitr) { (*hitr)->getUsage(usage); } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/PixelBufferWin32.cpp0000644000175000017500000006274113151044751025377 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. * * Some elements of GraphicsWindowWin32 have used the Producer implementation as a reference. * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004 Don Burns. */ #include #include #include #include #include #include #include #ifndef WGL_ARB_pbuffer #define WGL_ARB_pbuffer 1 DECLARE_HANDLE(HPBUFFERARB); #define WGL_DRAW_TO_PBUFFER_ARB 0x202D #define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E #define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F #define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 #define WGL_PBUFFER_LARGEST_ARB 0x2033 #define WGL_PBUFFER_WIDTH_ARB 0x2034 #define WGL_PBUFFER_HEIGHT_ARB 0x2035 #define WGL_PBUFFER_LOST_ARB 0x2036 #endif #ifndef WGL_ARB_pixel_format #define WGL_ARB_pixel_format 1 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NEED_PALETTE_ARB 0x2004 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 #define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 #define WGL_TRANSPARENT_ARB 0x200A #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B #define WGL_SHARE_DEPTH_ARB 0x200C #define WGL_SHARE_STENCIL_ARB 0x200D #define WGL_SHARE_ACCUM_ARB 0x200E #define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_STEREO_ARB 0x2012 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201A #define WGL_ALPHA_BITS_ARB 0x201B #define WGL_ALPHA_SHIFT_ARB 0x201C #define WGL_ACCUM_BITS_ARB 0x201D #define WGL_ACCUM_RED_BITS_ARB 0x201E #define WGL_ACCUM_GREEN_BITS_ARB 0x201F #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_NO_ACCELERATION_ARB 0x2025 #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_SWAP_EXCHANGE_ARB 0x2028 #define WGL_SWAP_COPY_ARB 0x2029 #define WGL_SWAP_UNDEFINED_ARB 0x202A #define WGL_TYPE_RGBA_ARB 0x202B #define WGL_TYPE_COLORINDEX_ARB 0x202C #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 #endif #ifndef WGL_ARB_render_texture #define WGL_ARB_render_texture 1 #define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 #define WGL_TEXTURE_FORMAT_ARB 0x2072 #define WGL_TEXTURE_TARGET_ARB 0x2073 #define WGL_MIPMAP_TEXTURE_ARB 0x2074 #define WGL_TEXTURE_RGB_ARB 0x2075 #define WGL_TEXTURE_RGBA_ARB 0x2076 #define WGL_NO_TEXTURE_ARB 0x2077 #define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 #define WGL_TEXTURE_1D_ARB 0x2079 #define WGL_TEXTURE_2D_ARB 0x207A #define WGL_MIPMAP_LEVEL_ARB 0x207B #define WGL_CUBE_MAP_FACE_ARB 0x207C #define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 #define WGL_FRONT_LEFT_ARB 0x2083 #define WGL_FRONT_RIGHT_ARB 0x2084 #define WGL_BACK_LEFT_ARB 0x2085 #define WGL_BACK_RIGHT_ARB 0x2086 #define WGL_AUX0_ARB 0x2087 #define WGL_AUX1_ARB 0x2088 #define WGL_AUX2_ARB 0x2089 #define WGL_AUX3_ARB 0x208A #define WGL_AUX4_ARB 0x208B #define WGL_AUX5_ARB 0x208C #define WGL_AUX6_ARB 0x208D #define WGL_AUX7_ARB 0x208E #define WGL_AUX8_ARB 0x208F #define WGL_AUX9_ARB 0x2090 #endif #ifndef WGL_NV_render_depth_texture #define WGL_NV_render_depth_texture 1 #define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 #define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 #define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 #define WGL_DEPTH_COMPONENT_NV 0x20A7 #endif #ifndef WGL_NV_render_texture_rectangle #define WGL_NV_render_texture_rectangle 1 #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 #define WGL_TEXTURE_RECTANGLE_NV 0x20A2 #endif #ifndef WGL_SAMPLE_BUFFERS_ARB #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #endif #ifndef WGL_SAMPLES_ARB #define WGL_SAMPLES_ARB 0x2042 #endif namespace { static std::string sysError() { DWORD stat, err = GetLastError(); LPVOID lpMsgBuf = 0; stat = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf,\ 0,NULL ); std::ostringstream msgResult; if ( stat > 0 && lpMsgBuf ) { msgResult << (LPCTSTR)lpMsgBuf; LocalFree( lpMsgBuf ); } else { msgResult << "Error code " << err; } return msgResult.str(); } static int __tempwnd_id = 0; class TemporaryWindow: public osg::Referenced { public: TemporaryWindow(): _handle(0), _dc(0), _context(0), _instance(0) { create(); } HWND getHandle() const { return _handle; } HDC getDC() const { return _dc; } HGLRC getContext() const { return _context; } bool makeCurrent(); protected: ~TemporaryWindow(); TemporaryWindow(const TemporaryWindow &): _handle(0), _dc(0), _context(0), _instance(0) {} TemporaryWindow &operator=(const TemporaryWindow &) { return *this; } void create(); void kill(); private: HWND _handle; HDC _dc; HGLRC _context; HINSTANCE _instance; std::string _classname; }; void TemporaryWindow::create() { std::ostringstream oss; oss << "tempwnd" << (++__tempwnd_id); _classname = oss.str(); _instance = GetModuleHandle(0); WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wndclass.lpfnWndProc = DefWindowProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = _instance; wndclass.hCursor = 0; wndclass.hIcon = 0; wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wndclass.lpszMenuName = 0; wndclass.lpszClassName = _classname.c_str(); if (!RegisterClass(&wndclass)) return; if (!(_handle = CreateWindowEx( 0, _classname.c_str(), TEXT(_classname.c_str()), WS_POPUP, 0, 0, 100, 100, 0, 0, _instance, 0))) { OSG_WARN << "PixelBufferWin32, could not create temporary window: " << sysError() << std::endl; kill(); return; } if (!(_dc = GetDC(_handle))) { OSG_WARN << "PixelBufferWin32, could not get device context for temporary window: " << sysError() << std::endl; kill(); return; } PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; int visual_id = ChoosePixelFormat(_dc, &pfd); if (!SetPixelFormat(_dc, visual_id, &pfd)) { OSG_WARN << "PixelBufferWin32, could not set pixel format for temporary window: " << sysError() << std::endl; kill(); return; } if (!(_context = wglCreateContext(_dc))) { OSG_WARN << "PixelBufferWin32, could not get graphics context for temporary window: " << sysError() << std::endl; kill(); return; } } TemporaryWindow::~TemporaryWindow() { kill(); } void TemporaryWindow::kill() { if (_context) { // mew 2005-05-09 commented out due to crashes. // possible causes are unsafe destructor ordering, or context already // deleted by window deletion; see: // http://openscenegraph.org/pipermail/osg-users/2005-May/052753.html //wglDeleteContext(_context); _context = 0; } if (_dc) { ReleaseDC(_handle, _dc); _dc = 0; } if (_handle) { DestroyWindow(_handle); _handle = 0; } UnregisterClass(_classname.c_str(), _instance); _instance = 0; } bool TemporaryWindow::makeCurrent() { bool result = wglMakeCurrent(_dc, _context) == TRUE ? true : false; if (!result) { OSG_NOTICE << "PixelBufferWin32, could not make the temporary window's context active: " << sysError() << std::endl; } return result; } class WGLExtensions : public osg::Referenced { public: typedef HPBUFFERARB (WINAPI * WGLCreatePBufferProc) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); typedef HDC (WINAPI * WGLGetPBufferDCProc) (HPBUFFERARB hPbuffer); typedef int (WINAPI * WGLReleasePBufferDCProc) (HPBUFFERARB hPbuffer, HDC hDC); typedef bool (WINAPI * WGLDestroyPBufferProc) (HPBUFFERARB hPbuffer); typedef bool (WINAPI * WGLQueryPBufferProc) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); typedef bool (WINAPI * WGLBindTexImageProc) (HPBUFFERARB hPbuffer, int iBuffer); typedef bool (WINAPI * WGLReleaseTexImageProc) (HPBUFFERARB hPbuffer, int iBuffer); typedef bool (WINAPI * WGLSetPbufferAttribProc) (HPBUFFERARB hPbuffer, const int * piAttribList); typedef bool (WINAPI * WGLChoosePixelFormatProc) (HDC, const int *, const float *, unsigned int, int *, unsigned int *); typedef bool (WINAPI * WGLMakeContextCurrentProc) (HDC, HDC, HGLRC); WGLCreatePBufferProc wglCreatePbufferARB; WGLGetPBufferDCProc wglGetPbufferDCARB; WGLReleasePBufferDCProc wglReleasePbufferDCARB; WGLDestroyPBufferProc wglDestroyPbufferARB; WGLQueryPBufferProc wglQueryPbufferARB; WGLBindTexImageProc wglBindTexImageARB; WGLReleaseTexImageProc wglReleaseTexImageARB; WGLChoosePixelFormatProc wglChoosePixelFormatARB; WGLMakeContextCurrentProc wglMakeContextCurrentARB; static WGLExtensions *instance(); bool isValid(); protected: WGLExtensions(); ~WGLExtensions(); private: static std::map > _instances; }; std::map > WGLExtensions::_instances; WGLExtensions::WGLExtensions() { wglCreatePbufferARB = (WGLCreatePBufferProc)wglGetProcAddress("wglCreatePbufferARB"); wglGetPbufferDCARB = (WGLGetPBufferDCProc)wglGetProcAddress("wglGetPbufferDCARB"); wglReleasePbufferDCARB = (WGLReleasePBufferDCProc)wglGetProcAddress("wglReleasePbufferDCARB"); wglDestroyPbufferARB = (WGLDestroyPBufferProc)wglGetProcAddress("wglDestroyPbufferARB"); wglQueryPbufferARB = (WGLQueryPBufferProc)wglGetProcAddress("wglQueryPbufferARB"); wglBindTexImageARB = (WGLBindTexImageProc)wglGetProcAddress("wglBindTexImageARB"); wglReleaseTexImageARB = (WGLReleaseTexImageProc)wglGetProcAddress("wglReleaseTexImageARB"); wglChoosePixelFormatARB = (WGLChoosePixelFormatProc)wglGetProcAddress("wglChoosePixelFormatARB"); wglMakeContextCurrentARB = (WGLMakeContextCurrentProc)wglGetProcAddress("wglMakeContextCurrentARB"); if (!wglMakeContextCurrentARB) { wglMakeContextCurrentARB = (WGLMakeContextCurrentProc)wglGetProcAddress("wglMakeContextCurrentEXT"); } } WGLExtensions::~WGLExtensions() { } bool WGLExtensions::isValid() { return (wglCreatePbufferARB && wglGetPbufferDCARB && wglReleasePbufferDCARB && wglDestroyPbufferARB && wglQueryPbufferARB && wglChoosePixelFormatARB ); } WGLExtensions *WGLExtensions::instance() { HGLRC context = wglGetCurrentContext(); // Get wgl function pointers for the current graphics context, or if there is no // current context then use a temporary window. if (!_instances[context]) { if ( context == 0 ) { osg::ref_ptr tempWin= new TemporaryWindow; tempWin->makeCurrent(); _instances[HGLRC(0)] = new WGLExtensions; } else { _instances[context] = new WGLExtensions; } } return _instances[context].get(); } } using namespace osgViewer; PixelBufferWin32::PixelBufferWin32( osg::GraphicsContext::Traits* traits ): _initialized(false), _valid(false), _realized(false), _boundBuffer(0) { _traits = traits; init(); if (valid()) { setState( new osg::State ); getState()->setGraphicsContext( this ); if (_traits.valid() && _traits->sharedContext.valid() ) { getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); incrementContextIDUsageCount( getState()->getContextID() ); } else { getState()->setContextID( osg::GraphicsContext::createNewContextID() ); } } } PixelBufferWin32::~PixelBufferWin32() { closeImplementation(); } void PixelBufferWin32::init() { if (_initialized) return; if (!_traits) return; if (!_traits->pbuffer) return; WGLExtensions* wgle = WGLExtensions::instance(); if (!wgle || !wgle->isValid()) { OSG_NOTICE << "PixelBufferWin32::init(), Error: some wgl extensions not supported" << std::endl; return; } std::vector fAttribList; std::vector bAttribList; fAttribList.push_back(WGL_DRAW_TO_PBUFFER_ARB); fAttribList.push_back(true); fAttribList.push_back(WGL_SUPPORT_OPENGL_ARB); fAttribList.push_back(true); fAttribList.push_back(WGL_PIXEL_TYPE_ARB); fAttribList.push_back(WGL_TYPE_RGBA_ARB); bAttribList.push_back(WGL_PBUFFER_LARGEST_ARB); bAttribList.push_back(true); fAttribList.push_back(WGL_RED_BITS_ARB); fAttribList.push_back(_traits->red); fAttribList.push_back(WGL_GREEN_BITS_ARB); fAttribList.push_back(_traits->green); fAttribList.push_back(WGL_BLUE_BITS_ARB); fAttribList.push_back(_traits->blue); if (_traits->alpha) { fAttribList.push_back(WGL_ALPHA_BITS_ARB); fAttribList.push_back(_traits->alpha); } fAttribList.push_back(WGL_DEPTH_BITS_ARB); fAttribList.push_back(_traits->depth); if (_traits->stencil) { fAttribList.push_back(WGL_STENCIL_BITS_ARB); fAttribList.push_back(_traits->stencil); } if (_traits->sampleBuffers) { fAttribList.push_back(WGL_SAMPLE_BUFFERS_ARB); fAttribList.push_back(_traits->sampleBuffers); fAttribList.push_back(WGL_SAMPLES_ARB); fAttribList.push_back(_traits->samples); } if (_traits->doubleBuffer) { fAttribList.push_back(WGL_DOUBLE_BUFFER_ARB); fAttribList.push_back(true); } if (_traits->target != 0 && wgle->wglBindTexImageARB ) { // TODO: Cube Maps if (_traits->target == GL_TEXTURE_RECTANGLE) { bAttribList.push_back(WGL_TEXTURE_TARGET_ARB); bAttribList.push_back(WGL_TEXTURE_RECTANGLE_NV); if (_traits->alpha) fAttribList.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV); else fAttribList.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV); fAttribList.push_back(true); } else { bAttribList.push_back(WGL_TEXTURE_TARGET_ARB); bAttribList.push_back(WGL_TEXTURE_2D_ARB); if (_traits->alpha) fAttribList.push_back(WGL_BIND_TO_TEXTURE_RGBA_ARB); else fAttribList.push_back(WGL_BIND_TO_TEXTURE_RGB_ARB); fAttribList.push_back(true); } bAttribList.push_back(WGL_TEXTURE_FORMAT_ARB); if (_traits->alpha) bAttribList.push_back(WGL_TEXTURE_RGBA_ARB); else bAttribList.push_back(WGL_TEXTURE_RGB_ARB); if (_traits->mipMapGeneration) { fAttribList.push_back(WGL_MIPMAP_TEXTURE_ARB); fAttribList.push_back(true); } } fAttribList.push_back(0); bAttribList.push_back(0); HDC hdc = 0; int format; osg::ref_ptr tempWin; tempWin = new TemporaryWindow; hdc = tempWin->getDC(); tempWin->makeCurrent(); wgle = WGLExtensions::instance(); unsigned int nformats = 0; wgle->wglChoosePixelFormatARB(hdc, &fAttribList[0], NULL, 1, &format, &nformats); if (nformats == 0) { OSG_NOTICE << "PixelBufferWin32::init(), Error: Couldn't find a suitable pixel format" << std::endl; return; } _hwnd = reinterpret_cast(wgle->wglCreatePbufferARB(hdc, format, _traits->width, _traits->height, &bAttribList[0])); if (!_hwnd) { OSG_NOTICE << "PixelBufferWin32::init, wglCreatePbufferARB error: " << sysError() << std::endl; return ; } _hdc = wgle->wglGetPbufferDCARB(reinterpret_cast(_hwnd)); if (!_hdc) { OSG_NOTICE << "PixelBufferWin32::init, wglGetPbufferDCARB error: " << sysError() << std::endl; return; } _hglrc = wglCreateContext(_hdc); if (!_hglrc) { OSG_NOTICE << "PixelBufferWin32::init, wglCreateContext error: " << sysError() << std::endl; return; } int iWidth = 0; int iHeight = 0; wgle->wglQueryPbufferARB(reinterpret_cast(_hwnd), WGL_PBUFFER_WIDTH_ARB, &iWidth); wgle->wglQueryPbufferARB(reinterpret_cast(_hwnd), WGL_PBUFFER_HEIGHT_ARB, &iHeight); if (_traits->width != iWidth || _traits->height != iHeight) { OSG_NOTICE << "PixelBufferWin32::init(), pbuffer created with different size then requsted" << std::endl; OSG_NOTICE << "\tRequested size (" << _traits->width << "," << _traits->height << ")" << std::endl; OSG_NOTICE << "\tPbuffer size (" << iWidth << "," << iHeight << ")" << std::endl; _traits->width = iWidth; _traits->height = iHeight; } _initialized = true; _valid = true; return; } bool PixelBufferWin32::realizeImplementation() { if (_realized) { OSG_NOTICE<<"PixelBufferWin32::realizeImplementation() Already realized"<sharedContext.valid() ) { GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast(_traits->sharedContext.get()); if (graphicsHandleWin32) { if ( !wglShareLists(graphicsHandleWin32->getWGLContext(), _hglrc) ) { OSG_NOTICE << "PixelBufferWin32::realizeImplementation, wglShareLists error: " << sysError() << std::endl; } } } _realized = true; return true; } void PixelBufferWin32::closeImplementation() { if (_hwnd) { WGLExtensions* wgle = WGLExtensions::instance(); wglMakeCurrent(NULL,NULL); if ( !wglDeleteContext(_hglrc) ) { OSG_NOTICE << "PixelBufferWin32::closeImplementation, wglDeleteContext error: " << sysError() << std::endl; } if (wgle && wgle->isValid()) { // Note that closeImplementation() should only be called from the same thread as created the pbuffer, // otherwise these routines will return an error. if ( !wgle->wglReleasePbufferDCARB(reinterpret_cast(_hwnd), _hdc) ) { OSG_NOTICE << "PixelBufferWin32::closeImplementation, wglReleasePbufferDCARB error: " << sysError() << std::endl; } if ( !wgle->wglDestroyPbufferARB(reinterpret_cast(_hwnd)) ) { OSG_NOTICE << "PixelBufferWin32::closeImplementation, wglDestroyPbufferARB error: " << sysError() << std::endl; } } } _valid = false; _initialized = false; _hwnd = 0; _hdc = 0; _hglrc = 0; } bool PixelBufferWin32::makeCurrentImplementation() { bool result = wglMakeCurrent(_hdc, _hglrc)==TRUE?true:false; if (!result) { OSG_NOTICE << "PixelBufferWin32::makeCurrentImplementation, wglMakeCurrent error: " << sysError() << std::endl; } // If the pbuffer is bound to a texture then release it. This operation requires a current context, so // do it after the MakeCurrent. if ( _boundBuffer!=0 ) { WGLExtensions* wgle = WGLExtensions::instance(); if ( wgle && wgle->wglReleaseTexImageARB ) { if ( !wgle->wglReleaseTexImageARB(reinterpret_cast(_hwnd), _boundBuffer) ) { OSG_NOTICE << "PixelBufferWin32::makeCurrentImplementation, wglReleaseTexImageARB error: " << sysError() << std::endl; } _boundBuffer=0; } } return result; } bool PixelBufferWin32::makeContextCurrentImplementation( GraphicsContext* readContext ) { WGLExtensions* wgle = WGLExtensions::instance(); if ( !wgle || !wgle->wglMakeContextCurrentARB ) { OSG_NOTICE << "PixelBufferWin32, wglMakeContextCurrentARB not available" << std::endl; return false; } GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast(readContext); if (graphicsHandleWin32) { return wgle->wglMakeContextCurrentARB(_hdc, graphicsHandleWin32->getHDC(), _hglrc); } return false; } bool PixelBufferWin32::releaseContextImplementation() { if (!_realized) { OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<wglBindTexImageARB ) { OSG_NOTICE << "PixelBufferWin32, wglBindTexImageARB not available" << std::endl; return; } int bindBuffer; switch (buffer) { case GL_BACK: bindBuffer = WGL_BACK_LEFT_ARB; break; case GL_FRONT: bindBuffer = WGL_FRONT_LEFT_ARB; break; default: bindBuffer = static_cast(buffer); } if ( bindBuffer != _boundBuffer ) { if ( _boundBuffer != 0 && !wgle->wglReleaseTexImageARB(reinterpret_cast(_hwnd), _boundBuffer) ) { OSG_NOTICE << "PixelBufferWin32::bindPBufferToTextureImplementation, wglReleaseTexImageARB error: " << sysError() << std::endl; } if ( !wgle->wglBindTexImageARB(reinterpret_cast(_hwnd), bindBuffer) ) { OSG_NOTICE << "PixelBufferWin32::bindPBufferToTextureImplementation, wglBindTexImageARB error: " << sysError() << std::endl; } _boundBuffer = bindBuffer; } } void PixelBufferWin32::swapBuffersImplementation() { SwapBuffers( _hdc ); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/GraphicsWindowWin32.cpp0000644000175000017500000032226513151044751026114 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. * * This file is Copyright (C) 2007 - Andre Garneau (andre@pixdev.com) and licensed under OSGPL. * * Some elements of GraphicsWindowWin32 have used the Producer implementation as a reference. * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004 Don Burns. */ #include #include #include #include #include #include #include #include #include #include #define MOUSEEVENTF_FROMTOUCH 0xFF515700 #if(WINVER < 0x0601) // Provide Declarations for Multitouch #define WM_TOUCH 0x0240 /* * Touch Input defines and functions */ /* * Touch input handle */ DECLARE_HANDLE(HTOUCHINPUT); typedef struct tagTOUCHINPUT { LONG x; LONG y; HANDLE hSource; DWORD dwID; DWORD dwFlags; DWORD dwMask; DWORD dwTime; ULONG_PTR dwExtraInfo; DWORD cxContact; DWORD cyContact; } TOUCHINPUT, *PTOUCHINPUT; typedef TOUCHINPUT const * PCTOUCHINPUT; /* * Conversion of touch input coordinates to pixels */ #define TOUCH_COORD_TO_PIXEL(l) ((l) / 100) /* * Touch input flag values (TOUCHINPUT.dwFlags) */ #define TOUCHEVENTF_MOVE 0x0001 #define TOUCHEVENTF_DOWN 0x0002 #define TOUCHEVENTF_UP 0x0004 #define TOUCHEVENTF_INRANGE 0x0008 #define TOUCHEVENTF_PRIMARY 0x0010 #define TOUCHEVENTF_NOCOALESCE 0x0020 #define TOUCHEVENTF_PEN 0x0040 #define TOUCHEVENTF_PALM 0x0080 #endif typedef BOOL (WINAPI GetTouchInputInfoFunc)( HTOUCHINPUT hTouchInput, // input event handle; from touch message lParam UINT cInputs, // number of elements in the array PTOUCHINPUT pInputs, // array of touch inputs int cbSize); // sizeof(TOUCHINPUT) typedef BOOL (WINAPI CloseTouchInputHandleFunc( HTOUCHINPUT hTouchInput)); // input event handle; from touch message lParam typedef BOOL (WINAPI RegisterTouchWindowFunc( HWND hwnd, ULONG ulFlags)); // Declared static in order to get Header File clean static RegisterTouchWindowFunc *registerTouchWindowFunc = NULL; static CloseTouchInputHandleFunc *closeTouchInputHandleFunc = NULL; static GetTouchInputInfoFunc *getTouchInputInfoFunc = NULL; using namespace osgViewer; namespace osgViewer { static osg::ApplicationUsageProxy GraphicsWindowWin32_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND on/off","Enable/disable duplicate makeCurrentContext call used as workaround for WinXP/NVidia/MultiView/MulitThread isues (pre 178.13 drivers)."); // // Defines from the WGL_ARB_pixel_format specification document // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt // #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NEED_PALETTE_ARB 0x2004 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 #define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 #define WGL_TRANSPARENT_ARB 0x200A #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B #define WGL_SHARE_DEPTH_ARB 0x200C #define WGL_SHARE_STENCIL_ARB 0x200D #define WGL_SHARE_ACCUM_ARB 0x200E #define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_STEREO_ARB 0x2012 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201A #define WGL_ALPHA_BITS_ARB 0x201B #define WGL_ALPHA_SHIFT_ARB 0x201C #define WGL_ACCUM_BITS_ARB 0x201D #define WGL_ACCUM_RED_BITS_ARB 0x201E #define WGL_ACCUM_GREEN_BITS_ARB 0x201F #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_NO_ACCELERATION_ARB 0x2025 #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_SWAP_EXCHANGE_ARB 0x2028 #define WGL_SWAP_COPY_ARB 0x2029 #define WGL_SWAP_UNDEFINED_ARB 0x202A #define WGL_TYPE_RGBA_ARB 0x202B #define WGL_TYPE_COLORINDEX_ARB 0x202C #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 #ifndef WGL_ARB_create_context #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define ERROR_INVALID_VERSION_ARB 0x2095 #endif #ifndef WGL_ARB_create_context #define WGL_ARB_create_context 1 #ifdef WGL_WGLEXT_PROTOTYPES extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); #endif /* WGL_WGLEXT_PROTOTYPES */ typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); #endif // // Entry points used from the WGL extensions // // BOOL wglChoosePixelFormatARB(HDC hdc, // const int *piAttribIList, // const FLOAT *pfAttribFList, // UINT nMaxFormats, // int *piFormats, // UINT *nNumFormats); // typedef bool (WINAPI * WGLChoosePixelFormatARB) ( HDC, const int *, const float *, unsigned int, int *, unsigned int * ); // // Utility class to specify the visual attributes for wglChoosePixelFormatARB() function // template class WGLAttributes { public: WGLAttributes() {} ~WGLAttributes() {} void begin() { m_parameters.clear(); } void set( const T& id, const T& value ) { add(id); add(value); } void enable( const T& id ) { add(id); add(true); } void disable( const T& id ) { add(id); add(false); } void end() { add(0); } const T* get() const { return &m_parameters.front(); } protected: void add( const T& t ) { m_parameters.push_back(t); } std::vector m_parameters; // parameters added private: // No implementation for these WGLAttributes( const WGLAttributes& ); WGLAttributes& operator=( const WGLAttributes& ); }; typedef WGLAttributes WGLIntegerAttributes; typedef WGLAttributes WGLFloatAttributes; // // Class responsible for interfacing with the Win32 Window Manager // The behavior of this class is specific to OSG needs and is not a // generic Windowing interface. // // NOTE: This class is intended to be used by a single-thread. // Multi-threading is not enabled for performance reasons. // The creation/deletion of graphics windows should be done // by a single controller thread. That thread should then // call the checkEvents() method of all created windows periodically. // This is the case with OSG as a "main" thread does all // setup, update & event processing. Rendering is done (optionally) by other threads. // // !@todo Have a dedicated thread managed by the Win32WindowingSystem class handle the // creation and event message processing for all windows it manages. This // is to relieve the "main" thread from having to do this synchronously // during frame generation. The "main" thread would only have to process // each osgGA-type window event queue. // class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface { public: // A class representing an OpenGL rendering context class OpenGLContext { public: OpenGLContext() : _previousHdc(0), _previousHglrc(0), _hwnd(0), _hdc(0), _hglrc(0), _restorePreviousOnExit(false) {} OpenGLContext( HWND hwnd, HDC hdc, HGLRC hglrc ) : _previousHdc(0), _previousHglrc(0), _hwnd(hwnd), _hdc(hdc), _hglrc(hglrc), _restorePreviousOnExit(false) {} ~OpenGLContext(); void set( HWND hwnd, HDC hdc, HGLRC hglrc ) { _hwnd = hwnd; _hdc = hdc; _hglrc = hglrc; } HDC deviceContext() { return _hdc; } bool makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit ); protected: // // Data members // HDC _previousHdc; // previously HDC to restore rendering context on HGLRC _previousHglrc; // previously current rendering context HWND _hwnd; // handle to OpenGL window HDC _hdc; // handle to device context HGLRC _hglrc; // handle to OpenGL rendering context bool _restorePreviousOnExit; // restore original context on exit private: // no implementation for these OpenGLContext( const OpenGLContext& ); OpenGLContext& operator=( const OpenGLContext& ); }; static std::string osgGraphicsWindowWithCursorClass; //!< Name of Win32 window class (with cursor) used by OSG graphics window instances static std::string osgGraphicsWindowWithoutCursorClass; //!< Name of Win32 window class (without cursor) used by OSG graphics window instances Win32WindowingSystem(); ~Win32WindowingSystem(); // Access the Win32 windowing system through this singleton class. static Win32WindowingSystem* getInterface() { static Win32WindowingSystem* win32Interface = new Win32WindowingSystem; return win32Interface; } // Return the number of screens present in the system virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si ); // Return the resolution of specified screen // (0,0) is returned if screen is unknown virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution ); // Return the bits per pixel of specified screen // (0) is returned if screen is unknown virtual void getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel ); // Set the resolution for given screen virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution ); // Enumerates available resolutions virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolution); // Return the screen position and width/height. // all zeros returned if screen is unknown virtual void getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height ); // Create a graphics context with given traits virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits ); // Register a newly created native window along with its application counterpart // This is required to maintain a link between Windows messages and the application window object // at event processing time virtual void registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window ); // Unregister a window // This is called as part of a window being torn down virtual void unregisterWindow( HWND hwnd ); // Get the application window object associated with a native window virtual osgViewer::GraphicsWindowWin32* getGraphicsWindowFor( HWND hwnd ); // Return a valid sample OpenGL Device Context and current rendering context that can be used with wglXYZ extensions virtual bool getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY ); protected: // Display devices present in the system typedef std::vector DisplayDevices; // Map Win32 window handles to GraphicsWindowWin32 instance typedef std::pair< HWND, osgViewer::GraphicsWindowWin32* > WindowHandleEntry; typedef std::map< HWND, osgViewer::GraphicsWindowWin32* > WindowHandles; // Enumerate all display devices and return in passed container void enumerateDisplayDevices( DisplayDevices& displayDevices ) const; // Get the screen device current mode information bool getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode ); // Change the screen settings (resolution, refresh rate, etc.) bool changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode ); // Register the window classes used by OSG graphics window instances void registerWindowClasses(); // Unregister the window classes used by OSG graphics window instances void unregisterWindowClasses(); // Data members WindowHandles _activeWindows; //!< handles to active windows bool _windowClassesRegistered; //!< true after window classes have been registered private: // No implementation for these Win32WindowingSystem( const Win32WindowingSystem& ); Win32WindowingSystem& operator=( const Win32WindowingSystem& ); }; /////////////////////////////////////////////////////////////////////////////// // Check if window dimensions have changed w.r.t stored values ////////////////////////////////////////////////////////////////////////////// static bool areWindowDimensionsChanged(HWND hwnd, int screenOriginX, int screenOriginY, int& windowX, int& windowY, int& windowWidth, int& windowHeight) { POINT origin; origin.x = 0; origin.y = 0; ::ClientToScreen(hwnd, &origin); int new_windowX = origin.x - screenOriginX; int new_windowY = origin.y - screenOriginY; RECT clientRect; ::GetClientRect(hwnd, &clientRect); int new_windowWidth = (clientRect.right == 0) ? 1 : clientRect.right; int new_windowHeight = (clientRect.bottom == 0) ? 1 : clientRect.bottom; if ((new_windowX != windowX) || (new_windowY != windowY) || (new_windowWidth != windowWidth) || (new_windowHeight != windowHeight)) { windowX = new_windowX; windowY = new_windowY; windowWidth = new_windowWidth; windowHeight = new_windowHeight; return true; } else { return false; } } /////////////////////////////////////////////////////////////////////////////// // Error reporting ////////////////////////////////////////////////////////////////////////////// static void reportError( const std::string& msg ) { OSG_WARN << "Error: " << msg.c_str() << std::endl; } static void reportError( const std::string& msg, unsigned int errorCode ) { // // Some APIs are documented as returning the error in ::GetLastError but apparently do not // Skip "Reason" field if the errorCode is still success // if (errorCode==0) { reportError(msg); return; } OSG_WARN << "Windows Error #" << errorCode << ": " << msg.c_str(); LPVOID lpMsgBuf; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, 0, // Default language (LPTSTR) &lpMsgBuf, 0, NULL)!=0) { OSG_WARN << ". Reason: " << LPTSTR(lpMsgBuf) << std::endl; ::LocalFree(lpMsgBuf); } else { OSG_WARN << std::endl; } } static void reportErrorForScreen( const std::string& msg, const osg::GraphicsContext::ScreenIdentifier& si, unsigned int errorCode ) { std::ostringstream str; str << "[Screen #" << si.screenNum << "] " << msg; reportError(str.str(), errorCode); } ////////////////////////////////////////////////////////////////////////////// // Keyboard key mapping for Win32 ////////////////////////////////////////////////////////////////////////////// class Win32KeyboardMap { public: Win32KeyboardMap() { _keymap[VK_ESCAPE ] = osgGA::GUIEventAdapter::KEY_Escape; _keymap[VK_F1 ] = osgGA::GUIEventAdapter::KEY_F1; _keymap[VK_F2 ] = osgGA::GUIEventAdapter::KEY_F2; _keymap[VK_F3 ] = osgGA::GUIEventAdapter::KEY_F3; _keymap[VK_F4 ] = osgGA::GUIEventAdapter::KEY_F4; _keymap[VK_F5 ] = osgGA::GUIEventAdapter::KEY_F5; _keymap[VK_F6 ] = osgGA::GUIEventAdapter::KEY_F6; _keymap[VK_F7 ] = osgGA::GUIEventAdapter::KEY_F7; _keymap[VK_F8 ] = osgGA::GUIEventAdapter::KEY_F8; _keymap[VK_F9 ] = osgGA::GUIEventAdapter::KEY_F9; _keymap[VK_F10 ] = osgGA::GUIEventAdapter::KEY_F10; _keymap[VK_F11 ] = osgGA::GUIEventAdapter::KEY_F11; _keymap[VK_F12 ] = osgGA::GUIEventAdapter::KEY_F12; _keymap[0xc0 ] = osgGA::GUIEventAdapter::KEY_Backquote; _keymap['0' ] = osgGA::GUIEventAdapter::KEY_0; _keymap['1' ] = osgGA::GUIEventAdapter::KEY_1; _keymap['2' ] = osgGA::GUIEventAdapter::KEY_2; _keymap['3' ] = osgGA::GUIEventAdapter::KEY_3; _keymap['4' ] = osgGA::GUIEventAdapter::KEY_4; _keymap['5' ] = osgGA::GUIEventAdapter::KEY_5; _keymap['6' ] = osgGA::GUIEventAdapter::KEY_6; _keymap['7' ] = osgGA::GUIEventAdapter::KEY_7; _keymap['8' ] = osgGA::GUIEventAdapter::KEY_8; _keymap['9' ] = osgGA::GUIEventAdapter::KEY_9; _keymap[0xbd ] = osgGA::GUIEventAdapter::KEY_Minus; _keymap[0xbb ] = osgGA::GUIEventAdapter::KEY_Equals; _keymap[VK_BACK ] = osgGA::GUIEventAdapter::KEY_BackSpace; _keymap[VK_TAB ] = osgGA::GUIEventAdapter::KEY_Tab; _keymap['A' ] = osgGA::GUIEventAdapter::KEY_A; _keymap['B' ] = osgGA::GUIEventAdapter::KEY_B; _keymap['C' ] = osgGA::GUIEventAdapter::KEY_C; _keymap['D' ] = osgGA::GUIEventAdapter::KEY_D; _keymap['E' ] = osgGA::GUIEventAdapter::KEY_E; _keymap['F' ] = osgGA::GUIEventAdapter::KEY_F; _keymap['G' ] = osgGA::GUIEventAdapter::KEY_G; _keymap['H' ] = osgGA::GUIEventAdapter::KEY_H; _keymap['I' ] = osgGA::GUIEventAdapter::KEY_I; _keymap['J' ] = osgGA::GUIEventAdapter::KEY_J; _keymap['K' ] = osgGA::GUIEventAdapter::KEY_K; _keymap['L' ] = osgGA::GUIEventAdapter::KEY_L; _keymap['M' ] = osgGA::GUIEventAdapter::KEY_M; _keymap['N' ] = osgGA::GUIEventAdapter::KEY_N; _keymap['O' ] = osgGA::GUIEventAdapter::KEY_O; _keymap['P' ] = osgGA::GUIEventAdapter::KEY_P; _keymap['Q' ] = osgGA::GUIEventAdapter::KEY_Q; _keymap['R' ] = osgGA::GUIEventAdapter::KEY_R; _keymap['S' ] = osgGA::GUIEventAdapter::KEY_S; _keymap['T' ] = osgGA::GUIEventAdapter::KEY_T; _keymap['U' ] = osgGA::GUIEventAdapter::KEY_U; _keymap['V' ] = osgGA::GUIEventAdapter::KEY_V; _keymap['W' ] = osgGA::GUIEventAdapter::KEY_W; _keymap['X' ] = osgGA::GUIEventAdapter::KEY_X; _keymap['Y' ] = osgGA::GUIEventAdapter::KEY_Y; _keymap['Z' ] = osgGA::GUIEventAdapter::KEY_Z; _keymap[0xdb ] = osgGA::GUIEventAdapter::KEY_Leftbracket; _keymap[0xdd ] = osgGA::GUIEventAdapter::KEY_Rightbracket; _keymap[0xdc ] = osgGA::GUIEventAdapter::KEY_Backslash; _keymap[VK_CAPITAL ] = osgGA::GUIEventAdapter::KEY_Caps_Lock; _keymap[0xba ] = osgGA::GUIEventAdapter::KEY_Semicolon; _keymap[0xde ] = osgGA::GUIEventAdapter::KEY_Quote; _keymap[VK_RETURN ] = osgGA::GUIEventAdapter::KEY_Return; _keymap[VK_LSHIFT ] = osgGA::GUIEventAdapter::KEY_Shift_L; _keymap[0xbc ] = osgGA::GUIEventAdapter::KEY_Comma; _keymap[0xbe ] = osgGA::GUIEventAdapter::KEY_Period; _keymap[0xbf ] = osgGA::GUIEventAdapter::KEY_Slash; _keymap[VK_RSHIFT ] = osgGA::GUIEventAdapter::KEY_Shift_R; _keymap[VK_LCONTROL ] = osgGA::GUIEventAdapter::KEY_Control_L; _keymap[VK_LWIN ] = osgGA::GUIEventAdapter::KEY_Super_L; _keymap[VK_SPACE ] = osgGA::GUIEventAdapter::KEY_Space; _keymap[VK_LMENU ] = osgGA::GUIEventAdapter::KEY_Alt_L; _keymap[VK_RMENU ] = osgGA::GUIEventAdapter::KEY_Alt_R; _keymap[VK_RWIN ] = osgGA::GUIEventAdapter::KEY_Super_R; _keymap[VK_APPS ] = osgGA::GUIEventAdapter::KEY_Menu; _keymap[VK_RCONTROL ] = osgGA::GUIEventAdapter::KEY_Control_R; _keymap[VK_SNAPSHOT ] = osgGA::GUIEventAdapter::KEY_Print; _keymap[VK_SCROLL ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock; _keymap[VK_PAUSE ] = osgGA::GUIEventAdapter::KEY_Pause; _keymap[VK_HOME ] = osgGA::GUIEventAdapter::KEY_Home; _keymap[VK_PRIOR ] = osgGA::GUIEventAdapter::KEY_Page_Up; _keymap[VK_END ] = osgGA::GUIEventAdapter::KEY_End; _keymap[VK_NEXT ] = osgGA::GUIEventAdapter::KEY_Page_Down; _keymap[VK_DELETE ] = osgGA::GUIEventAdapter::KEY_Delete; _keymap[VK_INSERT ] = osgGA::GUIEventAdapter::KEY_Insert; _keymap[VK_LEFT ] = osgGA::GUIEventAdapter::KEY_Left; _keymap[VK_UP ] = osgGA::GUIEventAdapter::KEY_Up; _keymap[VK_RIGHT ] = osgGA::GUIEventAdapter::KEY_Right; _keymap[VK_DOWN ] = osgGA::GUIEventAdapter::KEY_Down; _keymap[VK_NUMLOCK ] = osgGA::GUIEventAdapter::KEY_Num_Lock; _keymap[VK_DIVIDE ] = osgGA::GUIEventAdapter::KEY_KP_Divide; _keymap[VK_MULTIPLY ] = osgGA::GUIEventAdapter::KEY_KP_Multiply; _keymap[VK_SUBTRACT ] = osgGA::GUIEventAdapter::KEY_KP_Subtract; _keymap[VK_ADD ] = osgGA::GUIEventAdapter::KEY_KP_Add; _keymap[VK_NUMPAD7 ] = osgGA::GUIEventAdapter::KEY_KP_Home; _keymap[VK_NUMPAD8 ] = osgGA::GUIEventAdapter::KEY_KP_Up; _keymap[VK_NUMPAD9 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up; _keymap[VK_NUMPAD4 ] = osgGA::GUIEventAdapter::KEY_KP_Left; _keymap[VK_NUMPAD5 ] = osgGA::GUIEventAdapter::KEY_KP_Begin; _keymap[VK_NUMPAD6 ] = osgGA::GUIEventAdapter::KEY_KP_Right; _keymap[VK_NUMPAD1 ] = osgGA::GUIEventAdapter::KEY_KP_End; _keymap[VK_NUMPAD2 ] = osgGA::GUIEventAdapter::KEY_KP_Down; _keymap[VK_NUMPAD3 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down; _keymap[VK_NUMPAD0 ] = osgGA::GUIEventAdapter::KEY_KP_Insert; _keymap[VK_DECIMAL ] = osgGA::GUIEventAdapter::KEY_KP_Delete; _keymap[VK_CLEAR ] = osgGA::GUIEventAdapter::KEY_Clear; } ~Win32KeyboardMap() {} int remapKey(int key) { KeyMap::const_iterator map = _keymap.find(key); return map==_keymap.end() ? key : map->second; } protected: typedef std::map KeyMap; KeyMap _keymap; }; static Win32KeyboardMap s_win32KeyboardMap; static int remapWin32Key(int key) { return s_win32KeyboardMap.remapKey(key); } ////////////////////////////////////////////////////////////////////////////// // Window procedure for all GraphicsWindowWin32 instances // Dispatches the call to the actual instance ////////////////////////////////////////////////////////////////////////////// static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd); return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) : ::DefWindowProc(hwnd, uMsg, wParam, lParam); } ////////////////////////////////////////////////////////////////////////////// // Win32WindowingSystem::OpenGLContext implementation ////////////////////////////////////////////////////////////////////////////// Win32WindowingSystem::OpenGLContext::~OpenGLContext() { if (_restorePreviousOnExit && _previousHglrc!=_hglrc && !::wglMakeCurrent(_previousHdc, _previousHglrc)) { reportError("Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context", ::GetLastError()); } _previousHdc = 0; _previousHglrc = 0; if (_hglrc) { ::wglMakeCurrent(_hdc, NULL); ::wglDeleteContext(_hglrc); _hglrc = 0; } if (_hdc) { ::ReleaseDC(_hwnd, _hdc); _hdc = 0; } if (_hwnd) { ::DestroyWindow(_hwnd); _hwnd = 0; } } bool Win32WindowingSystem::OpenGLContext::makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit ) { if (_hdc==0 || _hglrc==0) return false; _previousHglrc = restorePreviousOnExit ? ::wglGetCurrentContext() : 0; _previousHdc = restoreOnHdc; if (_hglrc==_previousHglrc) return true; if (!::wglMakeCurrent(_hdc, _hglrc)) { reportError("Win32WindowingSystem::OpenGLContext() - Unable to set current OpenGL rendering context", ::GetLastError()); return false; } _restorePreviousOnExit = restorePreviousOnExit; return true; } ////////////////////////////////////////////////////////////////////////////// // Win32WindowingSystem implementation ////////////////////////////////////////////////////////////////////////////// std::string Win32WindowingSystem::osgGraphicsWindowWithCursorClass; std::string Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass; Win32WindowingSystem::Win32WindowingSystem() : _windowClassesRegistered(false) { // Detect presence of runtime support for multitouch HMODULE hModule = LoadLibrary("user32"); if (hModule) { registerTouchWindowFunc = (RegisterTouchWindowFunc *) GetProcAddress( hModule, "RegisterTouchWindow"); closeTouchInputHandleFunc = (CloseTouchInputHandleFunc *) GetProcAddress( hModule, "CloseTouchInputHandle"); getTouchInputInfoFunc = (GetTouchInputInfoFunc *) GetProcAddress( hModule, "GetTouchInputInfo"); if (!(registerTouchWindowFunc && closeTouchInputHandleFunc && getTouchInputInfoFunc)) { registerTouchWindowFunc = NULL; closeTouchInputHandleFunc = NULL; getTouchInputInfoFunc = NULL; FreeLibrary( hModule); } } } Win32WindowingSystem::~Win32WindowingSystem() { if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } unregisterWindowClasses(); } void Win32WindowingSystem::enumerateDisplayDevices( DisplayDevices& displayDevices ) const { for (unsigned int deviceNum=0;; ++deviceNum) { DISPLAY_DEVICE displayDevice; displayDevice.cb = sizeof(displayDevice); if (!::EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0)) break; // Do not track devices used for remote access (Terminal Services pseudo-displays, etc.) if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue; // Only return display devices that are attached to the desktop if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue; displayDevices.push_back(displayDevice); } } void Win32WindowingSystem::registerWindowClasses() { if (_windowClassesRegistered) return; // // Register the window classes used by OSG GraphicsWindowWin32 instances // std::ostringstream str; str << "OSG Graphics Window for Win32 [" << ::GetCurrentProcessId() << "]"; osgGraphicsWindowWithCursorClass = str.str() + "{ with cursor }"; osgGraphicsWindowWithoutCursorClass = str.str() + "{ without cursor }"; WNDCLASSEX wc; HINSTANCE hinst = ::GetModuleHandle(NULL); // // First class: class for OSG Graphics Window with a cursor enabled // wc.cbSize = sizeof(wc); wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hinst; wc.hIcon = ::LoadIcon(hinst, "OSG_ICON"); wc.hCursor = ::LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = 0; wc.lpszClassName = osgGraphicsWindowWithCursorClass.c_str(); wc.hIconSm = NULL; if (::RegisterClassEx(&wc)==0) { unsigned int lastError = ::GetLastError(); if (lastError!=ERROR_CLASS_ALREADY_EXISTS) { reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register first window class", lastError); return; } } // // Second class: class for OSG Graphics Window without a cursor // wc.hCursor = NULL; wc.lpszClassName = osgGraphicsWindowWithoutCursorClass.c_str(); if (::RegisterClassEx(&wc)==0) { unsigned int lastError = ::GetLastError(); if (lastError!=ERROR_CLASS_ALREADY_EXISTS) { reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register second window class", lastError); return; } } _windowClassesRegistered = true; } void Win32WindowingSystem::unregisterWindowClasses() { if (_windowClassesRegistered) { ::UnregisterClass(osgGraphicsWindowWithCursorClass.c_str(), ::GetModuleHandle(NULL)); ::UnregisterClass(osgGraphicsWindowWithoutCursorClass.c_str(), ::GetModuleHandle(NULL)); _windowClassesRegistered = false; } } bool Win32WindowingSystem::getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY ) { context.set(0, 0, 0); registerWindowClasses(); HWND hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, osgGraphicsWindowWithoutCursorClass.c_str(), NULL, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED, windowOriginX, windowOriginY, 1, 1, NULL, NULL, ::GetModuleHandle(NULL), NULL); if (hwnd==0) { reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create window", ::GetLastError()); return false; } // // Set the pixel format of the window // PIXELFORMATDESCRIPTOR pixelFormat = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; HDC hdc = ::GetDC(hwnd); if (hdc==0) { reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to get window device context", ::GetLastError()); ::DestroyWindow(hwnd); return false; } int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat); if (pixelFormatIndex==0) { reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to choose pixel format", ::GetLastError()); ::ReleaseDC(hwnd, hdc); ::DestroyWindow(hwnd); return false; } if (!::SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat)) { reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to set pixel format", ::GetLastError()); ::ReleaseDC(hwnd, hdc); ::DestroyWindow(hwnd); return false; } HGLRC hglrc = ::wglCreateContext(hdc); if (hglrc==0) { reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create an OpenGL rendering context", ::GetLastError()); ::ReleaseDC(hwnd, hdc); ::DestroyWindow(hwnd); return false; } context.set(hwnd, hdc, hglrc); if (!context.makeCurrent(windowHDC, true)) return false; return true; } unsigned int Win32WindowingSystem::getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si ) { return si.displayNum==0 ? ::GetSystemMetrics(SM_CMONITORS) : 0; } bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode ) { if (si.displayNum>0) { OSG_WARN << "Win32WindowingSystem::getScreenInformation() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl; return false; } DisplayDevices displayDevices; enumerateDisplayDevices(displayDevices); if (si.screenNum>=static_cast(displayDevices.size())) { OSG_WARN << "Win32WindowingSystem::getScreenInformation() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl; return false; } displayDevice = displayDevices[si.screenNum]; deviceMode.dmSize = sizeof(deviceMode); deviceMode.dmDriverExtra = 0; if (!::EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode)) { std::ostringstream str; str << "Win32WindowingSystem::getScreenInformation() - Unable to query information for screen number " << si.screenNum; reportError(str.str(), ::GetLastError()); return false; } return true; } void Win32WindowingSystem::getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution ) { DISPLAY_DEVICE displayDevice; DEVMODE deviceMode; if (!getScreenInformation(si, displayDevice, deviceMode)) deviceMode.dmFields = 0; // Set the fields to 0 so that it says 'nothing'. // Get resolution if ((deviceMode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != 0) { resolution.width = deviceMode.dmPelsWidth; resolution.height = deviceMode.dmPelsHeight; } else { resolution.width = 0; resolution.height = 0; } // Get refersh rate if ((deviceMode.dmFields & DM_DISPLAYFREQUENCY) != 0) { resolution.refreshRate = deviceMode.dmDisplayFrequency; if (resolution.refreshRate == 0 || resolution.refreshRate == 1) { // Windows specific: 0 and 1 represent the hhardware's default refresh rate. // If someone knows how to get this refresh rate (in Hz)... OSG_NOTICE << "Win32WindowingSystem::getScreenSettings() is not fully implemented (cannot retrieve the hardware's default refresh rate)."<0 && resolution.height>0) { deviceMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; deviceMode.dmPelsWidth = static_cast(resolution.width); deviceMode.dmPelsHeight = static_cast(resolution.height); } // Set refersh rate if (resolution.refreshRate>0) { deviceMode.dmFields |= DM_DISPLAYFREQUENCY; deviceMode.dmDisplayFrequency = static_cast(resolution.refreshRate); } // Set bits per pixel for color buffer if (resolution.colorDepth>0) { deviceMode.dmFields |= DM_BITSPERPEL; deviceMode.dmBitsPerPel = static_cast(resolution.colorDepth); } return changeScreenSettings(si, displayDevice, deviceMode); } void Win32WindowingSystem::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList) { resolutionList.clear(); if (si.displayNum>0) { OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl; return; } DisplayDevices displayDevices; enumerateDisplayDevices(displayDevices); if (si.screenNum>=static_cast(displayDevices.size())) { OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl; return; } DISPLAY_DEVICE displayDevice = displayDevices[si.screenNum]; // Do the enumeration DEVMODE deviceMode; static const unsigned int MAX_RESOLUTIONS = 4046; // Upper limit to avoid infinite (= very long) loop. for (unsigned int i=0; ipbuffer) { osg::ref_ptr pbuffer = new PixelBufferWin32(traits); if (pbuffer->valid()) return pbuffer.release(); else return 0; } else { registerWindowClasses(); osg::ref_ptr window = new GraphicsWindowWin32(traits); if (window->valid()) return window.release(); else return 0; } } void Win32WindowingSystem::registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window ) { if (hwnd) _activeWindows.insert(WindowHandleEntry(hwnd, window)); } // // Unregister a window // This is called as part of a window being torn down // void Win32WindowingSystem::unregisterWindow( HWND hwnd ) { if (hwnd) _activeWindows.erase(hwnd); } // // Get the application window object associated with a native window // osgViewer::GraphicsWindowWin32* Win32WindowingSystem::getGraphicsWindowFor( HWND hwnd ) { WindowHandles::const_iterator entry = _activeWindows.find(hwnd); return entry==_activeWindows.end() ? 0 : entry->second; } ////////////////////////////////////////////////////////////////////////////// // GraphicsWindowWin32 implementation ////////////////////////////////////////////////////////////////////////////// GraphicsWindowWin32::GraphicsWindowWin32( osg::GraphicsContext::Traits* traits ) : _currentCursor(0), _windowProcedure(0), _timeOfLastCheckEvents(-1.0), _screenOriginX(0), _screenOriginY(0), _screenWidth(0), _screenHeight(0), _windowOriginXToRealize(0), _windowOriginYToRealize(0), _windowWidthToRealize(0), _windowHeightToRealize(0), _initialized(false), _valid(false), _realized(false), _ownsWindow(true), _closeWindow(false), _destroyWindow(false), _destroying(false), _mouseCursor(InheritCursor), _appMouseCursor(LeftArrowCursor), _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues( false ) { _traits = traits; if (_traits->useCursor) setCursor(LeftArrowCursor); else setCursor(NoCursor); init(); if (valid()) { setState( new osg::State ); getState()->setGraphicsContext(this); if (_traits.valid() && _traits->sharedContext.valid()) { getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); incrementContextIDUsageCount( getState()->getContextID() ); } else { getState()->setContextID( osg::GraphicsContext::createNewContextID() ); } } } GraphicsWindowWin32::~GraphicsWindowWin32() { close(); destroyWindow(); } void GraphicsWindowWin32::init() { if (_initialized) return; // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); WindowData *windowData = _traits.valid() ? dynamic_cast(_traits->inheritedWindowData.get()) : 0; HWND windowHandle = windowData ? windowData->_hwnd : 0; _ownsWindow = windowHandle==0; _closeWindow = false; _destroyWindow = false; _destroying = false; _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle); _valid = _initialized; int windowX = 0, windowY = 0, windowWidth = 0, windowHeight = 0; if (_traits.valid()) { windowX = _traits->x; windowY = _traits->y; windowWidth = _traits->width; windowHeight = _traits->height; } if (areWindowDimensionsChanged(_hwnd, _screenOriginX, _screenOriginY, windowX, windowY, windowWidth, windowHeight)) { resized(windowX, windowY, windowWidth, windowHeight); } // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); // 2008/10/03 // Few days ago NVidia released WHQL certified drivers ver 178.13. // These drivers (as well as former beta ver 177.92) were free from the bug described below. // So it looks like its high time to make the workaround inactive by default. // If you happen to still use earlier drivers and have problems consider changing to new ones or // activate OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND macro def through CMake advanced vars. #ifdef OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND // 2008/05/12 // Workaround for Bugs in NVidia drivers for windows XP / multithreaded / dualview / multicore CPU // affects GeForce 6x00, 7x00, 8x00 boards (others were not tested) driver versions 174.xx - 175.xx // pre 174.xx had other issues so reverting is not an option (statitistics, fbo) // drivers release 175.16 is the latest currently available // // When using OpenGL in threaded app ( main thread sets up context / renderer thread draws using it ) // first wglMakeCurrent seems to not work right and screw OpenGL context driver data: // 1: successive drawing shows a number of artifacts in TriangleStrips and TriangleFans // 2: weird behaviour of FramBufferObjects (glGenFramebuffer generates already generated ids ...) // Looks like repeating wglMakeCurrent call fixes all these issues // wglMakeCurrent call can impact performance so I try to minimize number of // wglMakeCurrent calls by checking current HDC and GL context // and repeat wglMakeCurrent only when they change for current thread _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = true; #endif const char* str = getenv("OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND"); if (str) { _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = (strcmp(str, "on")==0 || strcmp(str, "ON")==0 || strcmp(str, "On")==0 ); } } bool GraphicsWindowWin32::createWindow() { unsigned int extendedStyle; unsigned int windowStyle; if (!determineWindowPositionAndStyle(_traits->screenNum, _traits->x, _traits->y, _traits->width, _traits->height, _traits->windowDecoration, _windowOriginXToRealize, _windowOriginYToRealize, _windowWidthToRealize, _windowHeightToRealize, windowStyle, extendedStyle)) { reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style"); return false; } _hwnd = ::CreateWindowEx(extendedStyle, _traits->useCursor ? Win32WindowingSystem::osgGraphicsWindowWithCursorClass.c_str() : Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass.c_str(), _traits->windowName.c_str(), windowStyle, _windowOriginXToRealize, _windowOriginYToRealize, _windowWidthToRealize, _windowHeightToRealize, NULL, NULL, ::GetModuleHandle(NULL), NULL); if (_hwnd==0) { reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create window", _traits->screenNum, ::GetLastError()); return false; } _hdc = ::GetDC(_hwnd); if (_hdc==0) { reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError()); destroyWindow(); _hwnd = 0; return false; } // // Set the pixel format according to traits specified // if (!setPixelFormat()) { ::ReleaseDC(_hwnd, _hdc); _hdc = 0; destroyWindow(); return false; } // // Create the OpenGL rendering context associated with this window // _hglrc = createContextImplementation(); if (_hglrc==0) { reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError()); ::ReleaseDC(_hwnd, _hdc); _hdc = 0; destroyWindow(); return false; } Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this); if (registerTouchWindowFunc) (*registerTouchWindowFunc)( _hwnd, 0); return true; } bool GraphicsWindowWin32::setWindow( HWND handle ) { if (_initialized) { reportErrorForScreen("GraphicsWindowWin32::setWindow() - Window already created; it cannot be changed", _traits->screenNum, ::GetLastError()); return false; } if (handle==0) { reportErrorForScreen("GraphicsWindowWin32::setWindow() - Invalid window handle passed", _traits->screenNum, ::GetLastError()); return false; } _hwnd = handle; if (_hwnd==0) { reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to retrieve native window handle", _traits->screenNum, ::GetLastError()); return false; } _hdc = ::GetDC(_hwnd); if (_hdc==0) { reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError()); _hwnd = 0; return false; } // // Check if we must set the pixel format of the inherited window // if (!setPixelFormat()) { reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to set the inherited window pixel format", _traits->screenNum, ::GetLastError()); ::ReleaseDC(_hwnd, _hdc); _hdc = 0; _hwnd = 0; return false; } _hglrc = createContextImplementation(); if (_hglrc==0) { reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError()); ::ReleaseDC(_hwnd, _hdc); _hdc = 0; _hwnd = 0; return false; } WindowData *windowData = _traits.get() ? dynamic_cast(_traits->inheritedWindowData.get()) : 0; if (!windowData || windowData->_installEventHandler) { if (!registerWindowProcedure()) { ::wglDeleteContext(_hglrc); _hglrc = 0; ::ReleaseDC(_hwnd, _hdc); _hdc = 0; _hwnd = 0; return false; } } Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this); _initialized = true; _valid = true; return true; } void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow ) { if (_destroying) return; _destroying = true; if (_graphicsThread && _graphicsThread->isRunning()) { // find all the viewers that might own use this graphics context osg::GraphicsContext::Cameras cameras = getCameras(); for(osg::GraphicsContext::Cameras::iterator it=cameras.begin(); it!=cameras.end(); ++it) { osgViewer::View* view = dynamic_cast((*it)->getView()); osgViewer::ViewerBase* viewerBase = view ? view->getViewerBase() : 0; if (viewerBase && viewerBase->areThreadsRunning()) { viewerBase->stopThreading(); } } } if (_hdc) { releaseContext(); if (_hglrc) { ::wglDeleteContext(_hglrc); _hglrc = 0; } ::ReleaseDC(_hwnd, _hdc); _hdc = 0; } (void)unregisterWindowProcedure(); if (_hwnd) { Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd); if (_ownsWindow && deleteNativeWindow) ::DestroyWindow(_hwnd); _hwnd = 0; } _initialized = false; _realized = false; _valid = false; _destroying = false; } void GraphicsWindowWin32::registerWindow() { Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this); } void GraphicsWindowWin32::unregisterWindow() { Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd); } bool GraphicsWindowWin32::registerWindowProcedure() { ::SetLastError(0); _windowProcedure = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(WindowProc)); unsigned int error = ::GetLastError(); if (_windowProcedure==0 && error) { reportErrorForScreen("GraphicsWindowWin32::registerWindowProcedure() - Unable to register window procedure", _traits->screenNum, error); return false; } return true; } bool GraphicsWindowWin32::unregisterWindowProcedure() { if (_windowProcedure==0 || _hwnd==0) return true; ::SetLastError(0); WNDPROC wndProc = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_windowProcedure)); unsigned int error = ::GetLastError(); if (wndProc==0 && error) { reportErrorForScreen("GraphicsWindowWin32::unregisterWindowProcedure() - Unable to unregister window procedure", _traits->screenNum, error); return false; } _windowProcedure = 0; return true; } bool GraphicsWindowWin32::determineWindowPositionAndStyle( unsigned int screenNum, int clientAreaX, int clientAreaY, unsigned int clientAreaWidth, unsigned int clientAreaHeight, bool decorated, int& x, int& y, unsigned int& w, unsigned int& h, unsigned int& style, unsigned int& extendedStyle ) { if (_traits==0) return false; // // Query the screen position and size // osg::GraphicsContext::ScreenIdentifier screenId(screenNum); Win32WindowingSystem* windowManager = Win32WindowingSystem::getInterface(); windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight); if (_screenWidth==0 || _screenHeight==0) return false; x = clientAreaX + _screenOriginX; y = clientAreaY + _screenOriginY; w = clientAreaWidth; h = clientAreaHeight; style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; extendedStyle = 0; if (decorated) { style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; if (_traits->supportsResize) style |= WS_SIZEBOX; extendedStyle = WS_EX_APPWINDOW | WS_EX_OVERLAPPEDWINDOW | WS_EX_ACCEPTFILES | WS_EX_LTRREADING; RECT corners; corners.left = x; corners.top = y; corners.right = x + w - 1; corners.bottom = y + h - 1; // // Determine the location of the window corners in order to have // a client area of the requested size // if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle)) { reportErrorForScreen("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", _traits->screenNum, ::GetLastError()); return false; } x = corners.left; y = corners.top; w = corners.right - corners.left + 1; h = corners.bottom - corners.top + 1; } return true; } static void PreparePixelFormatSpecifications( const osg::GraphicsContext::Traits& traits, WGLIntegerAttributes& attributes, bool allowSwapExchangeARB ) { attributes.begin(); attributes.enable(WGL_DRAW_TO_WINDOW_ARB); attributes.enable(WGL_SUPPORT_OPENGL_ARB); attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB); attributes.set(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); attributes.set(WGL_COLOR_BITS_ARB, traits.red + traits.green + traits.blue); attributes.set(WGL_RED_BITS_ARB, traits.red); attributes.set(WGL_GREEN_BITS_ARB, traits.green); attributes.set(WGL_BLUE_BITS_ARB, traits.blue); attributes.set(WGL_DEPTH_BITS_ARB, traits.depth); if (traits.doubleBuffer) { attributes.enable(WGL_DOUBLE_BUFFER_ARB); switch ( traits.swapMethod ) { case osg::DisplaySettings::SWAP_COPY: attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_COPY_ARB); break; case osg::DisplaySettings::SWAP_EXCHANGE: attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB); break; case osg::DisplaySettings::SWAP_UNDEFINED: attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_UNDEFINED_ARB); break; case osg::DisplaySettings::SWAP_DEFAULT: // Wojtek Lewandowski 2010-09-28: // Keep backward compatibility if no method is selected via traits // and let wglSwapExchangeARB flag select swap method. // However, I would rather remove this flag because its // now redundant to Traits::swapMethod and it looks like // WGL_SWAP_EXCHANGE_ARB is the GL default when no WGL_SWAP attrib is given. // To be precise: At least on Windows 7 and Nvidia it seems to be a default. if ( allowSwapExchangeARB ) attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB); break; } } if (traits.alpha) attributes.set(WGL_ALPHA_BITS_ARB, traits.alpha); if (traits.stencil) attributes.set(WGL_STENCIL_BITS_ARB, traits.stencil); if (traits.sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, traits.sampleBuffers); if (traits.samples) attributes.set(WGL_SAMPLES_ARB, traits.samples); if (traits.quadBufferStereo) attributes.enable(WGL_STEREO_ARB); attributes.end(); } static int ChooseMatchingPixelFormat( HDC hdc, int screenNum, const WGLIntegerAttributes& formatSpecifications ,osg::GraphicsContext::Traits* _traits) { // // Access the entry point for the wglChoosePixelFormatARB function // WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB"); if (wglChoosePixelFormatARB==0) { // = openGLContext.getTraits() reportErrorForScreen("ChooseMatchingPixelFormat() - wglChoosePixelFormatARB extension not found, trying GDI", screenNum, ::GetLastError()); PIXELFORMATDESCRIPTOR pixelFormat = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number PFD_DRAW_TO_WINDOW | // support window PFD_SUPPORT_OPENGL | // support OpenGL (_traits->doubleBuffer ? PFD_DOUBLEBUFFER : NULL) | // double buffered ? (_traits->swapMethod == osg::DisplaySettings::SWAP_COPY ? PFD_SWAP_COPY : NULL) | (_traits->swapMethod == osg::DisplaySettings::SWAP_EXCHANGE ? PFD_SWAP_EXCHANGE : NULL), PFD_TYPE_RGBA, // RGBA type _traits->red + _traits->green + _traits->blue, // color depth _traits->red ,0, _traits->green ,0, _traits->blue, 0, // shift bits ignored _traits->alpha, // alpha buffer ? 0, // shift bit ignored 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored _traits->depth, // 32 or 16 bit z-buffer ? _traits->stencil, // stencil buffer ? 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat); if (pixelFormatIndex == 0) { reportErrorForScreen("ChooseMatchingPixelFormat() - GDI ChoosePixelFormat Failed.", screenNum, ::GetLastError()); return -1; } ::DescribePixelFormat(hdc, pixelFormatIndex ,sizeof(PIXELFORMATDESCRIPTOR),&pixelFormat); if (((pixelFormat.dwFlags & PFD_GENERIC_FORMAT) != 0) && ((pixelFormat.dwFlags & PFD_GENERIC_ACCELERATED) == 0)) { OSG_WARN << "Rendering in software: pixelFormatIndex " << pixelFormatIndex << std::endl; } return pixelFormatIndex; } int pixelFormatIndex = 0; unsigned int numMatchingPixelFormats = 0; if (!wglChoosePixelFormatARB(hdc, formatSpecifications.get(), NULL, 1, &pixelFormatIndex, &numMatchingPixelFormats)) { reportErrorForScreen("ChooseMatchingPixelFormat() - Unable to choose the requested pixel format", screenNum, ::GetLastError()); return -1; } return numMatchingPixelFormats==0 ? -1 : pixelFormatIndex; } bool GraphicsWindowWin32::setPixelFormat() { Win32WindowingSystem::OpenGLContext openGLContext; if (!Win32WindowingSystem::getInterface()->getSampleOpenGLContext(openGLContext, _hdc, _screenOriginX, _screenOriginY)) return false; // // Build the specifications of the requested pixel format // WGLIntegerAttributes formatSpecs; ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true); // // Choose the closest matching pixel format from the specified traits // int pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get()); if (pixelFormatIndex<0) { unsigned int bpp; Win32WindowingSystem::getInterface()->getScreenColorDepth(*_traits.get(), bpp); if (bpp < 32) { OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Display setting is not 32 bit colors, " << bpp << " bits per pixel on screen #" << _traits->screenNum << std::endl; _traits->red = bpp / 4; //integer divide, determine minimum number of bits we will accept _traits->green = bpp / 4; _traits->blue = bpp / 4; ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);// try again with WGL_SWAP_METHOD_ARB pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get()); } } if (pixelFormatIndex<0) { ::PreparePixelFormatSpecifications(*_traits, formatSpecs, false); pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get()); if (pixelFormatIndex<0) { reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", _traits->screenNum, 0); return false; } OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Found a matching pixel format but without the WGL_SWAP_METHOD_ARB specification for screen #" << _traits->screenNum << std::endl; } // // Set the pixel format found // PIXELFORMATDESCRIPTOR pfd; ::memset(&pfd, 0, sizeof(pfd)); pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd)) { reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", _traits->screenNum, ::GetLastError()); return false; } return true; } HGLRC GraphicsWindowWin32::createContextImplementation() { HGLRC context( NULL ); if( OSG_GL3_FEATURES ) { OSG_NOTIFY( osg::INFO ) << "GL3: Attempting to create OpenGL3 context." << std::endl; OSG_NOTIFY( osg::INFO ) << "GL3: version: " << _traits->glContextVersion << std::endl; OSG_NOTIFY( osg::INFO ) << "GL3: context flags: " << _traits->glContextFlags << std::endl; OSG_NOTIFY( osg::INFO ) << "GL3: profile: " << _traits->glContextProfileMask << std::endl; Win32WindowingSystem::OpenGLContext openGLContext; if( !Win32WindowingSystem::getInterface()->getSampleOpenGLContext( openGLContext, _hdc, _screenOriginX, _screenOriginY ) ) { reportErrorForScreen( "GL3: Can't create sample context.", _traits->screenNum, ::GetLastError() ); } else { PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress( "wglCreateContextAttribsARB" ); if( wglCreateContextAttribsARB==0 ) { reportErrorForScreen( "GL3: wglCreateContextAttribsARB not available.", _traits->screenNum, ::GetLastError() ); } else { unsigned int idx( 0 ); int attribs[ 16 ]; unsigned int major = 1, minor = 0; if( !_traits->getContextVersion(major, minor) || major<3 ) { OSG_NOTIFY( osg::WARN ) << "GL3: Non-GL3 version number: " << _traits->glContextVersion << std::endl; } attribs[ idx++ ] = WGL_CONTEXT_MAJOR_VERSION_ARB; attribs[ idx++ ] = major; attribs[ idx++ ] = WGL_CONTEXT_MINOR_VERSION_ARB; attribs[ idx++ ] = minor; if( _traits->glContextFlags != 0 ) { attribs[ idx++ ] = WGL_CONTEXT_FLAGS_ARB; attribs[ idx++ ] = _traits->glContextFlags; } if( _traits->glContextProfileMask != 0 ) { attribs[ idx++ ] = WGL_CONTEXT_PROFILE_MASK_ARB; attribs[ idx++ ] = _traits->glContextProfileMask; } attribs[ idx++ ] = 0; context = wglCreateContextAttribsARB( _hdc, 0, attribs ); if( context == NULL ) { reportErrorForScreen( "GL3: wglCreateContextAttribsARB returned NULL.", _traits->screenNum, ::GetLastError() ); } else { OSG_NOTIFY( osg::INFO ) << "GL3: context created successfully." << std::endl; } } } } // TBD insert GL ES 2 suppurt, if required for Win32. // If platform context creation fails for any reason, // we'll create a standard context. This means you could // build OSG for GL3, have the context creation fail // (because you have the wrong driver), and end up with // a GL3 context. Something else will likely fail down // the line, as the GL3-built OSG will assume GL3 features // are present. // // This is also the typical path for GL 1/2 context creation. if( context == NULL ) context = ::wglCreateContext(_hdc); return( context ); } bool GraphicsWindowWin32::setWindowDecorationImplementation( bool decorated ) { unsigned int windowStyle; unsigned int extendedStyle; // // Determine position and size of window with/without decorations to retain the size specified in traits // int x, y; unsigned int w, h; if (!determineWindowPositionAndStyle(_traits->screenNum, _traits->x, _traits->y, _traits->width, _traits->height, decorated, x, y, w, h, windowStyle, extendedStyle)) { reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style", _traits->screenNum, 0); return false; } // // Change the window style // ::SetLastError(0); unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle); unsigned int error = ::GetLastError(); if (result==0 && error) { reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", _traits->screenNum, error); return false; } // // Change the window extended style // ::SetLastError(0); result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle); error = ::GetLastError(); if (result==0 && error) { reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", _traits->screenNum, error); return false; } // // Change the window position and size and realize the style changes // if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW)) { reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", _traits->screenNum, ::GetLastError()); return false; } // // Force a repaint of the desktop // ::InvalidateRect(NULL, NULL, TRUE); return true; } bool GraphicsWindowWin32::realizeImplementation() { if (_realized) return true; if (!_initialized) { init(); if (!_initialized) return false; } if (_traits.valid() && (_traits->sharedContext.valid() || _traits->vsync || _traits->swapGroupEnabled)) { // make context current so we can test capabilities and set up context sharing struct RestoreContext { RestoreContext() { _hdc = wglGetCurrentDC(); _hglrc = wglGetCurrentContext(); } ~RestoreContext() { wglMakeCurrent(_hdc,_hglrc); } protected: HDC _hdc; HGLRC _hglrc; } restoreContext; _realized = true; bool result = makeCurrent(); _realized = false; if (!result) { return false; } // set up sharing of contexts if required GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast(_traits->sharedContext.get()); if (graphicsHandleWin32) { if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext())) { reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError()); return false; } } // if vysnc should be on then enable it. if (_traits->vsync) { setSyncToVBlank(_traits->vsync); } // If the swap group is active then enable it. if (_traits->swapGroupEnabled) { setSwapGroup(_traits->swapGroupEnabled, _traits->swapGroup, _traits->swapBarrier); } } if (_ownsWindow) { // // Bring the window on top of other ones (including the taskbar if it covers it completely) // // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST // Z-order must be used in the code below instead of HWND_TOP. // @todo: This should be controlled through a flag in the traits (topMostWindow) // if (!::SetWindowPos(_hwnd, HWND_TOP, _windowOriginXToRealize, _windowOriginYToRealize, _windowWidthToRealize, _windowHeightToRealize, SWP_SHOWWINDOW)) { reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError()); return false; } if (!::UpdateWindow(_hwnd)) { reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError()); return false; } } _realized = true; // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); return true; } bool GraphicsWindowWin32::makeCurrentImplementation() { if (!_realized) { reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.", _traits->screenNum, 0); return false; } if( _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues ) { if( ::wglGetCurrentDC() != _hdc || ::wglGetCurrentContext() != _hglrc ) { if (!::wglMakeCurrent(_hdc, _hglrc)) { reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError()); return false; } } } if (!::wglMakeCurrent(_hdc, _hglrc)) { reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError()); return false; } return true; } bool GraphicsWindowWin32::releaseContextImplementation() { if (!::wglMakeCurrent(_hdc, NULL)) { reportErrorForScreen("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", _traits->screenNum, ::GetLastError()); return false; } return true; } void GraphicsWindowWin32::closeImplementation() { destroyWindow(); _initialized = false; _valid = false; _realized = false; } void GraphicsWindowWin32::swapBuffersImplementation() { if (!_realized) return; if (!::SwapBuffers(_hdc) && ::GetLastError() != 0) { reportErrorForScreen("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", _traits->screenNum, ::GetLastError()); } } bool GraphicsWindowWin32::checkEvents() { if (!_realized) return false; MSG msg; while (::PeekMessage(&msg, _hwnd, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } if (_closeWindow) { _closeWindow = false; close(); } if (_destroyWindow) { _destroyWindow = false; destroyWindow(false); } return !(getEventQueue()->empty()); } void GraphicsWindowWin32::grabFocus() { if (!::SetForegroundWindow(_hwnd)) { OSG_WARN << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl; } } void GraphicsWindowWin32::grabFocusIfPointerInWindow() { POINT mousePos; if (!::GetCursorPos(&mousePos)) { reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", _traits->screenNum, ::GetLastError()); return; } RECT windowRect; if (!::GetWindowRect(_hwnd, &windowRect)) { reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", _traits->screenNum, ::GetLastError()); return; } if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right && mousePos.y>=windowRect.top && mousePos.y<=windowRect.bottom) { grabFocus(); } } void GraphicsWindowWin32::requestWarpPointer( float x, float y ) { if (!_realized) { OSG_INFO<<"GraphicsWindowWin32::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<screenNum, ::GetLastError()); return; } if (!::SetCursorPos(windowRect.left + x, windowRect.top + y)) { reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError()); return; } #else // MIKEC: NEW CODE POINT pt; pt.x = (LONG)x; pt.y = (LONG)y; // convert point in client area coordinates to screen coordinates if (!::ClientToScreen(_hwnd, &pt)) { reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to convert cursor position to screen coordinates", _traits->screenNum, ::GetLastError()); } if (!::SetCursorPos(pt.x, pt.y)) { reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError()); return; } #endif getEventQueue()->mouseWarped(x,y); } bool GraphicsWindowWin32::setWindowRectangleImplementation(int x, int y, int width, int height) { unsigned int windowStyle; unsigned int extendedStyle; // // Determine position and size of window with/without decorations to retain the size specified in traits // int wx, wy; unsigned int ww, wh; if (!determineWindowPositionAndStyle(_traits->screenNum, x, y, width, height, _traits->windowDecoration, wx, wy, ww, wh, windowStyle, extendedStyle)) { reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to determine the window position and style", _traits->screenNum, 0); return false; } if (!::SetWindowPos(_hwnd, HWND_TOP, wx, wy, ww, wh, SWP_SHOWWINDOW | SWP_FRAMECHANGED)) { reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to set new window position and size", _traits->screenNum, ::GetLastError()); return false; } return true; } void GraphicsWindowWin32::setWindowName( const std::string & name ) { _traits->windowName = name; SetWindowText(_hwnd, name.c_str()); } void GraphicsWindowWin32::useCursor( bool cursorOn ) { if (_traits.valid()) _traits->useCursor = cursorOn; // note, we are using setCursorImpl to set the cursor, so we can use // _appMouseCursor to cache the current mouse-cursor setCursorImpl(cursorOn ? _appMouseCursor : NoCursor); } void GraphicsWindowWin32::setCursor( MouseCursor mouseCursor ) { _appMouseCursor = mouseCursor; setCursorImpl(mouseCursor); } void GraphicsWindowWin32::setCursorImpl( MouseCursor mouseCursor ) { if (_mouseCursor != mouseCursor) { _mouseCursor = mouseCursor; HCURSOR newCursor = getOrCreateCursor( mouseCursor); if (newCursor == _currentCursor) return; _currentCursor = newCursor; _traits->useCursor = (_currentCursor != NULL) && (_mouseCursor != NoCursor); PostMessage(_hwnd, WM_SETCURSOR, 0, 0); } } HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor) { std::map::iterator i = _mouseCursorMap.find(mouseCursor); if (i != _mouseCursorMap.end()) return i->second; switch (mouseCursor) { case NoCursor: _mouseCursorMap[mouseCursor] = NULL; break; case RightArrowCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW); break; case LeftArrowCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW); break; case InfoCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL); break; case DestroyCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO ); break; case HelpCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HELP ); break; case CycleCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO ); break; case SprayCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL ); break; case WaitCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_WAIT); break; case TextCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_IBEAM ); break; case CrosshairCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_CROSS ); break; case UpDownCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENS ); break; case LeftRightCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE ); break; case TopSideCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW ); break; case BottomSideCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW ); break; case LeftSideCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE); break; case RightSideCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE ); break; case TopLeftCorner: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE ); break; case TopRightCorner: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW ); break; case BottomRightCorner: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE ); break; case BottomLeftCorner: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW ); break; case HandCursor: _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HAND ); break; default: break; } return _mouseCursorMap[mouseCursor]; } void GraphicsWindowWin32::setSwapGroup(bool on, GLuint group, GLuint barrier) { if (_traits.valid()) { _traits->swapGroupEnabled = on; _traits->swapGroup = group; _traits->swapBarrier = barrier; } typedef BOOL (GL_APIENTRY *PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); PFNWGLJOINSWAPGROUPNVPROC wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC)wglGetProcAddress( "wglJoinSwapGroupNV" ); typedef BOOL (GL_APIENTRY *PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); PFNWGLBINDSWAPBARRIERNVPROC wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC)wglGetProcAddress( "wglBindSwapBarrierNV" ); if ((!wglJoinSwapGroupNV) || (!wglBindSwapBarrierNV)) { OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV(bool, GLuint, GLuint) not supported" << std::endl; return; } int swapGroup = (on ? group : 0); BOOL resultJoin = wglJoinSwapGroupNV(_hdc, swapGroup); OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV (" << swapGroup << ") returned " << resultJoin << std::endl; int swapBarrier = (on ? barrier : 0); BOOL resultBind = wglBindSwapBarrierNV(swapGroup, swapBarrier); OSG_INFO << "GraphicsWindowWin32::wglBindSwapBarrierNV (" << swapGroup << ", " << swapBarrier << ") returned " << resultBind << std::endl; } void GraphicsWindowWin32::setSyncToVBlank( bool on ) { if (_traits.valid()) { _traits->vsync = on; } //#if 0 // we ought to properly check if the extension is listed as supported rather than just // if the function pointer resolves through wglGetProcAddress, but in practice everything // supports this extension typedef BOOL (GL_APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int ); PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0; wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" ); if( wglSwapIntervalEXT ) { int swapInterval = (on ? 1 : 0); wglSwapIntervalEXT(swapInterval); OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank " << (on ? "on" : "off") << std::endl; } else { OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not supported" << std::endl; } //#else // OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not yet implemented."<< std::endl; //#endif } void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask, int& unmodifiedKeySymbol) { modifierMask = 0; bool rightSide = (lParam & 0x01000000)!=0; int virtualKey = ::MapVirtualKeyEx((lParam>>16) & 0xff, 3, ::GetKeyboardLayout(0)); BYTE keyState[256]; if (virtualKey==0 || !::GetKeyboardState(keyState)) { keySymbol = 0; return; } switch (virtualKey) { ////////////////// case VK_LSHIFT : ////////////////// modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT; break; ////////////////// case VK_RSHIFT : ////////////////// modifierMask |= osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT; break; ////////////////// case VK_CONTROL : case VK_LCONTROL : ////////////////// virtualKey = rightSide ? VK_RCONTROL : VK_LCONTROL; modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL; break; ////////////////// case VK_MENU : case VK_LMENU : ////////////////// virtualKey = rightSide ? VK_RMENU : VK_LMENU; modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT; break; ////////////////// default : ////////////////// virtualKey = wParam; break; } if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK; if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK; keySymbol = remapWin32Key(virtualKey); if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide) { keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter; } unmodifiedKeySymbol = keySymbol; if ((keySymbol & 0xff00)==0) { char asciiKey[2]; int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast(asciiKey), 0); if (numChars>0) keySymbol = asciiKey[0]; } } void GraphicsWindowWin32::transformMouseXY( float& x, float& y ) { if (getEventQueue()->getUseFixedMouseInputRange()) { osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState(); x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width); y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height); } } LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) return TRUE; //!@todo adapt windows event time to osgGA event queue time for better resolution double eventTime = getEventQueue()->getTime(); _timeOfLastCheckEvents = eventTime; switch(uMsg) { // Wojtek Lewandowski 2010-09-28: // All web docs on Windows Aero and OpenGL compatibiltiy // suggest WM_ERASEBKGND should be handled with non NULL value return. // This sugesstion may be irrelevant for our window class // as default brush pattern is not set so erase flag is forwarded to WM_PAINT // and gets ignored when WM_PAINT is handled. // But it will certainly be safer and not make things worse // if we handle this message to be sure everything is done as suggested. case WM_ERASEBKGND : return TRUE; break; ///////////////// case WM_PAINT : ///////////////// if (_ownsWindow) { PAINTSTRUCT paint; ::BeginPaint(hwnd, &paint); ::EndPaint(hwnd, &paint); requestRedraw(); } break; /////////////////// case WM_MOUSEMOVE : /////////////////// { float mx = GET_X_LPARAM(lParam); float my = GET_Y_LPARAM(lParam); transformMouseXY(mx, my); getEventQueue()->mouseMotion(mx, my, eventTime); } break; ///////////////////// case WM_LBUTTONDOWN : case WM_MBUTTONDOWN : case WM_RBUTTONDOWN : ///////////////////// { ::SetCapture(hwnd); int button; if (uMsg==WM_LBUTTONDOWN) button = 1; else if (uMsg==WM_MBUTTONDOWN) button = 2; else button = 3; _capturedMouseButtons.insert(button); float mx = GET_X_LPARAM(lParam); float my = GET_Y_LPARAM(lParam); transformMouseXY(mx, my); getEventQueue()->mouseButtonPress(mx, my, button, eventTime); } break; ///////////////////// case WM_LBUTTONUP : case WM_MBUTTONUP : case WM_RBUTTONUP : ///////////////////// { int button; if (uMsg==WM_LBUTTONUP) button = 1; else if (uMsg==WM_MBUTTONUP) button = 2; else button = 3; _capturedMouseButtons.erase(button); if(_capturedMouseButtons.empty()) ::ReleaseCapture(); float mx = GET_X_LPARAM(lParam); float my = GET_Y_LPARAM(lParam); transformMouseXY(mx, my); getEventQueue()->mouseButtonRelease(mx, my, button, eventTime); } break; /////////////////////// case WM_LBUTTONDBLCLK : case WM_MBUTTONDBLCLK : case WM_RBUTTONDBLCLK : /////////////////////// { ::SetCapture(hwnd); int button; if (uMsg==WM_LBUTTONDBLCLK) button = 1; else if (uMsg==WM_MBUTTONDBLCLK) button = 2; else button = 3; _capturedMouseButtons.insert(button); float mx = GET_X_LPARAM(lParam); float my = GET_Y_LPARAM(lParam); transformMouseXY(mx, my); getEventQueue()->mouseDoubleButtonPress(mx, my, button, eventTime); } break; //////////////////// case WM_MOUSEWHEEL : //////////////////// getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP, eventTime); break; ///////////////// case WM_MOVE : case WM_SIZE : ///////////////// { int windowX=_traits->x, windowY=_traits->y, windowWidth=_traits->width, windowHeight=_traits->height; if (areWindowDimensionsChanged(hwnd, _screenOriginX, _screenOriginY, windowX, windowY, windowWidth, windowHeight)) { resized(windowX, windowY, windowWidth, windowHeight); getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, eventTime); // request redraw if window size was changed if (windowWidth!=_traits->width || windowHeight!=_traits->height) requestRedraw(); } } break; //////////////////// case WM_KEYDOWN : case WM_SYSKEYDOWN : //////////////////// { int keySymbol = 0; int unmodifiedKeySymbol = 0; unsigned int modifierMask = 0; adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol); _keyMap[std::make_pair(keySymbol,unmodifiedKeySymbol)] = true; //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol); } break; ////////////////// case WM_KEYUP : case WM_SYSKEYUP : ////////////////// { int keySymbol = 0; int unmodifiedKeySymbol = 0; unsigned int modifierMask = 0; adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol); _keyMap[std::make_pair(keySymbol, unmodifiedKeySymbol)] = false; //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol); } break; /////////////////// case WM_SETCURSOR : /////////////////// //The cursor is only modified in response to the WM_SETCURSOR message if the mouse cursor isn't set to //InheritCursor. InheritCursor lets the user manage the cursor externally. if (_mouseCursor != InheritCursor) { if (_traits->useCursor) ::SetCursor( _currentCursor); else ::SetCursor(NULL); return TRUE; } break; /////////////////// case WM_SETFOCUS : /////////////////// // Check keys and send a message if the key is pressed when the // focus comes back to the window. // I don't really like this hard-coded loop, but the key codes // (VK_* constants) seem to go from 0x08 to 0xFE so it should be // ok. See winuser.h for the key codes. for (unsigned int i = 0x08; i < 0xFF; i++) { // Wojciech Lewandowski: 2011/09/12 // Skip CONTROL | MENU | SHIFT tests because we are polling exact left or right keys // above return press for both right and left so we may end up with incosistent // modifier mask if we report left control & right control while only right was pressed LONG rightSideCode = 0; switch( i ) { case VK_CONTROL: case VK_SHIFT: case VK_MENU: continue; case VK_RCONTROL: case VK_RSHIFT: case VK_RMENU: rightSideCode = 0x01000000; } if ((::GetAsyncKeyState(i) & 0x8000) != 0) { // Compute lParam because subsequent adaptKey will rely on correct lParam UINT scanCode = ::MapVirtualKeyEx( i, 0, ::GetKeyboardLayout(0)); // Set Extended Key bit + Scan Code + 30 bit to indicate key was set before sending message // See Windows SDK help on WM_KEYDOWN for explanation LONG lParam = rightSideCode | ( ( scanCode & 0xFF ) << 16 ) | (1 << 30); ::SendMessage(hwnd, WM_KEYDOWN, i, lParam ); } } break; /////////////////// case WM_KILLFOCUS : /////////////////// // Release all keys that were pressed when the window lost focus. for (std::map, bool>::iterator key = _keyMap.begin(); key != _keyMap.end(); ++key) { if (key->second) { getEventQueue()->keyRelease(key->first.first, key->first.second); key->second = false; } } _capturedMouseButtons.clear(); break; /////////////////// case WM_NCHITTEST : /////////////////// { LONG_PTR result = _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) : ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam); switch(result) { case HTLEFT: case HTRIGHT: setCursorImpl(LeftRightCursor); break; case HTTOP: case HTBOTTOM: setCursorImpl(UpDownCursor); break; case HTTOPLEFT: setCursorImpl(TopLeftCorner); break; case HTTOPRIGHT: setCursorImpl(TopRightCorner); break; case HTBOTTOMLEFT: setCursorImpl(BottomLeftCorner); break; case HTBOTTOMRIGHT: case HTGROWBOX: setCursorImpl(BottomRightCorner); break; case HTSYSMENU: case HTCAPTION: case HTMAXBUTTON: case HTMINBUTTON: case HTCLOSE: case HTHELP: setCursorImpl(LeftArrowCursor); break; default: if (_traits->useCursor && _appMouseCursor != InheritCursor) setCursorImpl(_appMouseCursor); break; } return result; } break; ///////////////// case WM_CLOSE : ///////////////// getEventQueue()->closeWindow(eventTime); break; ///////////////// case WM_DESTROY : ///////////////// _destroyWindow = true; if (_ownsWindow) { ::PostQuitMessage(0); } break; ////////////// case WM_QUIT : ////////////// _closeWindow = true; return wParam; ////////////// case WM_TOUCH: ///////////// { unsigned int numInputs = (unsigned int) wParam; TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; osg::ref_ptr osg_event(NULL); if(getTouchInputInfoFunc && (*getTouchInputInfoFunc)((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // For each contact, dispatch the message to the appropriate message handler. for(unsigned int i=0; i< numInputs; ++i) { if(ti[i].dwFlags & TOUCHEVENTF_DOWN) { if (!osg_event) { osg_event = getEventQueue()->touchBegan( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100 , ti[i].y/100); } else { osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100, ti[i].y/100); } } else if(ti[i].dwFlags & TOUCHEVENTF_MOVE) { if (!osg_event) { osg_event = getEventQueue()->touchMoved( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x/ 100, ti[i].y/ 100); } else { osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x / 100, ti[i].y/100); } } else if(ti[i].dwFlags & TOUCHEVENTF_UP) { // No double tap detection with RAW TOUCH Events, sorry. if (!osg_event) { osg_event = getEventQueue()->touchEnded( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x/ 100, ti[i].y/ 100, 1); } else { osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x / 100, ti[i].y/100); } } } } if (closeTouchInputHandleFunc) (*closeTouchInputHandleFunc)((HTOUCHINPUT)lParam); delete [] ti; } break; ///////////////// default : ///////////////// if (_ownsWindow) return ::DefWindowProc(hwnd, uMsg, wParam, lParam); break; } if (_ownsWindow) return 0; return _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) : ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam); } ////////////////////////////////////////////////////////////////////////////// // Class responsible for registering the Win32 Windowing System interface ////////////////////////////////////////////////////////////////////////////// struct RegisterWindowingSystemInterfaceProxy { RegisterWindowingSystemInterfaceProxy() { osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface()); } ~RegisterWindowingSystemInterfaceProxy() { if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } osg::GraphicsContext::setWindowingSystemInterface(0); } }; static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy; } // namespace OsgViewer // declare C entry point for static compilation. extern "C" void OSGVIEWER_EXPORT graphicswindow_Win32(void) { osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface()); } void GraphicsWindowWin32::raiseWindow() { SetWindowPos(_hwnd, HWND_TOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE); SetWindowPos(_hwnd, HWND_NOTOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/GraphicsWindow.cpp0000644000175000017500000000314713151044751025264 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osgViewer; void GraphicsWindow::getViews(Views& views) { views.clear(); osgViewer::View *prev = NULL; for(Cameras::iterator it = _cameras.begin(); it != _cameras.end(); it++) { osgViewer::View *v = dynamic_cast((*it)->getView()); if (v) // perform a simple test to reduce the number of duplicates if (v != prev) // append view views.push_back(v); } // remove duplicates views.sort(); views.unique(); } void GraphicsWindow::requestRedraw() { Views views; getViews(views); if (views.empty()) { OSG_INFO << "GraphicsWindow::requestRedraw(): No views assigned yet." << std::endl; return; } for(Views::iterator it = views.begin(); it != views.end(); it++) { (*it)->requestRedraw(); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/Viewer.cpp0000644000175000017500000013402513151044751023575 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; Viewer::Viewer() { _viewerBase = this; constructorInit(); } Viewer::Viewer(osg::ArgumentParser& arguments) { _viewerBase = this; constructorInit(); // Add help for command-line options read here arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select SingleThreaded threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select CullDrawThreadPerContext threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select DrawThreadPerContext threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select CullThreadPerCameraDrawThreadPerContext threading model for viewer."); arguments.getApplicationUsage()->addCommandLineOption("--clear-color ","Set the background color of the viewer in the form \"r,g,b[,a]\"."); arguments.getApplicationUsage()->addCommandLineOption("--screen ","Set the screen to use when multiple screens are present."); arguments.getApplicationUsage()->addCommandLineOption("--window ","Set the position (x,y) and size (w,h) of the viewer window."); arguments.getApplicationUsage()->addCommandLineOption("--run-on-demand","Set the run methods frame rate management to only rendering frames when required."); arguments.getApplicationUsage()->addCommandLineOption("--run-continuous","Set the run methods frame rate management to rendering frames continuously."); arguments.getApplicationUsage()->addCommandLineOption("--run-max-frame-rate","Set the run methods maximum permissible frame rate, 0.0 is default and switching off frame rate capping."); arguments.getApplicationUsage()->addCommandLineOption("--enable-object-cache","Enable caching of objects, images, etc."); // FIXME: Uncomment these lines when the options have been documented properly //arguments.getApplicationUsage()->addCommandLineOption("--3d-sd",""); //arguments.getApplicationUsage()->addCommandLineOption("--panoramic-sd",""); //arguments.getApplicationUsage()->addCommandLineOption("--radius",""); //arguments.getApplicationUsage()->addCommandLineOption("--collar",""); //arguments.getApplicationUsage()->addCommandLineOption("--im",""); if (arguments.read("--ico")) { setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation()); } std::string filename; bool readConfig = false; while (arguments.read("-c",filename)) { readConfig = readConfiguration(filename) || readConfig; } // Enable caching? while (arguments.read("--enable-object-cache")) { if (osgDB::Registry::instance()->getOptions()==0) osgDB::Registry::instance()->setOptions(new osgDB::Options()); osgDB::Registry::instance()->getOptions()->setObjectCacheHint(osgDB::Options::CACHE_ALL); } while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded); while (arguments.read("--CullDrawThreadPerContext")) setThreadingModel(CullDrawThreadPerContext); while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext); while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) setThreadingModel(CullThreadPerCameraDrawThreadPerContext); osg::DisplaySettings::instance()->readCommandLine(arguments); osgDB::readCommandLine(arguments); std::string colorStr; while (arguments.read("--clear-color",colorStr)) { float r, g, b; float a = 1.0f; int cnt = sscanf( colorStr.c_str(), "%f,%f,%f,%f", &r, &g, &b, &a ); if( cnt==3 || cnt==4 ) { getCamera()->setClearColor( osg::Vec4(r,g,b,a) ); } else { OSG_WARN<<"Invalid clear color \""< wow = new WoWVxDisplay; if (screenNum>=0) wow->setScreenNum(screenNum); if (wowvx20) wow->WoWVx20(); if (wowvx42) wow->WoWVx42(); unsigned int c; float v; while (arguments.read("--wow-content",c)) { wow->setContent(c); } while (arguments.read("--wow-factor",c)) { wow->setFactor(c); } while (arguments.read("--wow-offset",c)) { wow->setOffset(c); } while (arguments.read("--wow-zd",v)) { wow->setDisparityZD(v); } while (arguments.read("--wow-vz",v)) { wow->setDisparityVZ(v); } while (arguments.read("--wow-M",v)) { wow->setDisparityM(v); } while (arguments.read("--wow-C",v)) { wow->setDisparityC(v); } apply(wow.get()); } else if ((ss3d=arguments.read("--3d-sd")) || arguments.read("--panoramic-sd")) { double radius = 1.0; while (arguments.read("--radius",radius)) {} double collar = 0.45; while (arguments.read("--collar",collar)) {} std::string intensityMapFilename; while (arguments.read("--im",intensityMapFilename)) {} osg::ref_ptr intensityMap = intensityMapFilename.empty() ? 0 : osgDB::readRefImageFile(intensityMapFilename); if (screenNum<0) screenNum = 0; if (ss3d) { setThreadingModel(SingleThreaded); setUpViewFor3DSphericalDisplay(radius, collar, screenNum, intensityMap.get()); } else { setThreadingModel(SingleThreaded); setUpViewForPanoramicSphericalDisplay(radius, collar, screenNum, intensityMap.get()); } } else if (width>0 && height>0) { if (screenNum>=0) setUpViewInWindow(x, y, width, height, screenNum); else setUpViewInWindow(x,y,width,height); } else if (screenNum>=0) { setUpViewOnSingleScreen(screenNum); } } Viewer::Viewer(const osgViewer::Viewer& viewer, const osg::CopyOp& copyop): osg::Object(true), ViewerBase(viewer), View(viewer,copyop) { _viewerBase = this; } void Viewer::constructorInit() { _eventVisitor = new osgGA::EventVisitor; _eventVisitor->setActionAdapter(this); _eventVisitor->setFrameStamp(_frameStamp.get()); _updateVisitor = new osgUtil::UpdateVisitor; _updateVisitor->setFrameStamp(_frameStamp.get()); setViewerStats(new osg::Stats("Viewer")); } Viewer::~Viewer() { //OSG_NOTICE<<"Viewer::~Viewer()"< object = osgDB::readRefObjectFile(filename); if (!object) { //OSG_NOTICE<<"Error: Unable to load configuration file \""<(object.get()); if (config) { OSG_INFO<<"Using osgViewer::Config : "<className()<configure(*this); //osgDB::writeObjectFile(*config,"test.osgt"); return true; } CompositeViewer* compositeViewer = dynamic_cast(object.get()); if (compositeViewer) { OSG_NOTICE<<"Error: Config file \""<(object.get()); if (view) { take(*view); return true; } else { OSG_NOTICE<<"Error: Config file \""<(this)->getContexts(contexts); unsigned int numRealizedWindows = 0; // clear out all the previously assigned operations for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { if ((*citr)->isRealized()) ++numRealizedWindows; } return numRealizedWindows > 0; } bool Viewer::checkNeedToDoFrame() { // check if any event handler has prompted a redraw if (_requestRedraw) return true; if (_requestContinousUpdate) return true; // check if the database pager needs to update the scene if (getDatabasePager()->requiresUpdateSceneGraph() || getDatabasePager()->getRequestsInProgress()) return true; // check if there are camera update callbacks if (_camera->getUpdateCallback()) return true; // check if there are node update callbacks if (getSceneData() != 0) { if (getSceneData()->getUpdateCallback() || (getSceneData()->getNumChildrenRequiringUpdateTraversal()>0) ) return true; } // check if events are available and need processing if (checkEvents()) return true; // and check again if any event handler has prompted a redraw if (_requestRedraw) return true; if (_requestContinousUpdate) return true; return false; } bool Viewer::checkEvents() { // check events from any attached sources for(Devices::iterator eitr = _eventSources.begin(); eitr != _eventSources.end(); ++eitr) { osgGA::Device* es = eitr->get(); if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS) { if (es->checkEvents()) return true; } } // get events from all windows attached to Viewer. Windows windows; getWindows(windows); for(Windows::iterator witr = windows.begin(); witr != windows.end(); ++witr) { if ((*witr)->checkEvents()) return true; } return false; } int Viewer::run() { if (!getCameraManipulator() && getCamera()->getAllowEventFocus()) { setCameraManipulator(new osgGA::TrackballManipulator()); } setReleaseContextAtEndOfFrameHint(false); return ViewerBase::run(); } void Viewer::setStartTick(osg::Timer_t tick) { View::setStartTick(tick); Contexts contexts; getContexts(contexts,false); getEventQueue()->setStartTick(_startTick); for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->getEventQueue()->setStartTick(_startTick); } } } void Viewer::setReferenceTime(double time) { osg::Timer_t tick = osg::Timer::instance()->tick(); double currentTime = osg::Timer::instance()->delta_s(_startTick, tick); double delta_ticks = (time-currentTime)/(osg::Timer::instance()->getSecondsPerTick()); if (delta_ticks>=0) tick += osg::Timer_t(delta_ticks); else tick -= osg::Timer_t(-delta_ticks); // assign the new start tick setStartTick(tick); } void Viewer::setSceneData(osg::Node* node) { setReferenceTime(0.0); View::setSceneData(node); } GraphicsWindowEmbedded* Viewer::setUpViewerAsEmbeddedInWindow(int x, int y, int width, int height) { setThreadingModel(SingleThreaded); osgViewer::GraphicsWindowEmbedded* gw = new osgViewer::GraphicsWindowEmbedded(x,y,width,height); getCamera()->setViewport(new osg::Viewport(0,0,width,height)); getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(width)/static_cast(height), 1.0f, 10000.0f); getCamera()->setGraphicsContext(gw); return gw; } void Viewer::realize() { //OSG_INFO<<"Viewer::realize()"<> x >> y >> width >> height; } if (width>0 && height>0) { if (screenNum>=0) setUpViewInWindow(x, y, width, height, screenNum); else setUpViewInWindow(x,y,width,height); } else if (screenNum>=0) { setUpViewOnSingleScreen(screenNum); } else { setUpViewAcrossAllScreens(); } } getContexts(contexts); } if (contexts.empty()) { OSG_NOTICE<<"Viewer::realize() - failed to set up any windows"<getDisplaySettings()==0) wsi->setDisplaySettings(ds); unsigned int maxTexturePoolSize = ds->getMaxTexturePoolSize(); unsigned int maxBufferObjectPoolSize = ds->getMaxBufferObjectPoolSize(); for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osg::GraphicsContext* gc = *citr; if (ds->getSyncSwapBuffers()) gc->setSwapCallback(new osg::SyncSwapBuffersCallback); // set the pool sizes, 0 the default will result in no GL object pools. gc->getState()->setMaxTexturePoolSize(maxTexturePoolSize); gc->getState()->setMaxBufferObjectPoolSize(maxBufferObjectPoolSize); gc->realize(); if (_realizeOperation.valid() && gc->valid()) { gc->makeCurrent(); (*_realizeOperation)(gc); gc->releaseContext(); } } // attach contexts to _incrementalCompileOperation if attached. if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); bool grabFocus = true; if (grabFocus) { for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->grabFocusIfPointerInWindow(); } } } // initialize the global timer to be relative to the current time. osg::Timer::instance()->setStartTick(); // pass on the start tick to all the associated event queues setStartTick(osg::Timer::instance()->getStartTick()); // configure threading. setUpThreading(); if (osg::DisplaySettings::instance()->getCompileContextsHint()) { int numProcessors = OpenThreads::GetNumberOfProcessors(); int processNum = 0; for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i) { osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i); if (gc) { gc->createGraphicsThread(); gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors); gc->getGraphicsThread()->startThread(); ++processNum; } } } #if 0 osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState(); if (getCamera()->getViewport()) { osg::Viewport* viewport = getCamera()->getViewport(); eventState->setInputRange( viewport->x(), viewport->y(), viewport->x() + viewport->width(), viewport->y() + viewport->height()); } else { eventState->setInputRange(-1.0, -1.0, 1.0, 1.0); } #endif } void Viewer::advance(double simulationTime) { if (_done) return; double previousReferenceTime = _frameStamp->getReferenceTime(); unsigned int previousFrameNumber = _frameStamp->getFrameNumber(); _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1); _frameStamp->setReferenceTime( osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()) ); if (simulationTime==USE_REFERENCE_TIME) { _frameStamp->setSimulationTime(_frameStamp->getReferenceTime()); } else { _frameStamp->setSimulationTime(simulationTime); } if (getViewerStats() && getViewerStats()->collectStats("frame_rate")) { // update previous frame stats double deltaFrameTime = _frameStamp->getReferenceTime() - previousReferenceTime; getViewerStats()->setAttribute(previousFrameNumber, "Frame duration", deltaFrameTime); getViewerStats()->setAttribute(previousFrameNumber, "Frame rate", 1.0/deltaFrameTime); // update current frames stats getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Reference time", _frameStamp->getReferenceTime()); } if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->flush(); osg::Referenced::getDeleteHandler()->setFrameNumber(_frameStamp->getFrameNumber()); } } void Viewer::generateSlavePointerData(osg::Camera* camera, osgGA::GUIEventAdapter& event) { osgViewer::GraphicsWindow* gw = dynamic_cast(event.getGraphicsContext()); if (!gw) return; // What type of Camera is it? // 1) Master Camera : do nothin extra // 2) Slave Camera, Relative RF, Same scene graph as master : transform coords into Master Camera and add to PointerData list // 3) Slave Camera, Relative RF, Different scene graph from master : do nothing extra? // 4) Slave Camera, Absolute RF, Same scene graph as master : do nothing extra? // 5) Slave Camera, Absolute RF, Different scene graph : do nothing extra? // 6) Slave Camera, Absolute RF, Different scene graph but a distortion correction subgraph depending upon RTT Camera (slave or master) // : project ray into RTT Camera's clip space, and RTT Camera's is Relative RF and sharing same scene graph as master then transform coords. // if camera isn't the master it must be a slave and could need reprojecting. if (camera!=getCamera()) { float x = event.getX(); float y = event.getY(); bool invert_y = event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; double master_min_x = -1.0; double master_max_x = 1.0; double master_min_y = -1.0; double master_max_y = 1.0; osg::Matrix masterCameraVPW = getCamera()->getViewMatrix() * getCamera()->getProjectionMatrix(); if (getCamera()->getViewport()) { osg::Viewport* viewport = getCamera()->getViewport(); master_min_x = viewport->x(); master_min_y = viewport->y(); master_max_x = viewport->x()+viewport->width(); master_max_y = viewport->y()+viewport->height(); masterCameraVPW *= viewport->computeWindowMatrix(); } // slave Camera if it shares the same View osg::View::Slave* slave = findSlaveForCamera(camera); if (slave) { if (camera->getReferenceFrame()==osg::Camera::RELATIVE_RF && slave->_useMastersSceneData) { osg::Viewport* viewport = camera->getViewport(); osg::Matrix localCameraVPW = camera->getViewMatrix() * camera->getProjectionMatrix(); if (viewport) { localCameraVPW *= viewport->computeWindowMatrix(); } osg::Matrix matrix( osg::Matrix::inverse(localCameraVPW) * masterCameraVPW ); osg::Vec3d new_coord = osg::Vec3d(x,y,0.0) * matrix; event.addPointerData(new osgGA::PointerData(getCamera(), new_coord.x(), master_min_x, master_max_x, new_coord.y(), master_min_y, master_max_y)); } else if (!slave->_useMastersSceneData) { // Are their any RTT Camera's that this Camera depends upon for textures? osg::ref_ptr ray = new osgUtil::RayIntersector(osgUtil::Intersector::WINDOW, x,y); osgUtil::IntersectionVisitor iv(ray.get()); camera->accept(iv); if (ray->containsIntersections()) { osg::Vec3 tc; osg::Texture* texture = ray->getFirstIntersection().getTextureLookUp(tc); if (texture) { // look up Texture in RTT Camera's. for(unsigned int i=0; igetBufferAttachmentMap().find(osg::Camera::COLOR_BUFFER); if (ba_itr != slave_camera->getBufferAttachmentMap().end()) { if (ba_itr->second._texture == texture) { osg::TextureRectangle* tr = dynamic_cast(ba_itr->second._texture.get()); osg::TextureCubeMap* tcm = dynamic_cast(ba_itr->second._texture.get()); if (tr) { event.addPointerData(new osgGA::PointerData(slave_camera, tc.x(), 0.0f, static_cast(tr->getTextureWidth()), tc.y(), 0.0f, static_cast(tr->getTextureHeight()))); } else if (tcm) { OSG_INFO<<" Slave has matched texture cubemap"<second._texture.get()<<", "<second._face<(event.getGraphicsContext()); if (!gw) return; float x = event.getX(); float y = event.getY(); bool invert_y = event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; event.addPointerData(new osgGA::PointerData(gw, x, 0, gw->getTraits()->width, y, 0, gw->getTraits()->height)); event.setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); typedef std::vector CameraVector; CameraVector activeCameras; osgViewer::View* this_view = dynamic_cast(this); osg::GraphicsContext::Cameras& cameras = gw->getCameras(); for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { osg::Camera* camera = *citr; if (camera->getView()==this_view && camera->getAllowEventFocus() && camera->getRenderTargetImplementation()==osg::Camera::FRAME_BUFFER) { osg::Viewport* viewport = camera ? camera->getViewport() : 0; if (viewport && x >= viewport->x() && y >= viewport->y() && x <= (viewport->x()+viewport->width()) && y <= (viewport->y()+viewport->height()) ) { activeCameras.push_back(camera); } } } std::sort(activeCameras.begin(), activeCameras.end(), osg::CameraRenderOrderSortOp()); osg::Camera* camera = activeCameras.empty() ? 0 : activeCameras.back(); if (camera) { osg::Viewport* viewport = camera ? camera->getViewport() : 0; event.addPointerData(new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0, (y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0)); // if camera isn't the master it must be a slave and could need reprojecting. if (camera!=getCamera()) { generateSlavePointerData(camera, event); } } } void Viewer::reprojectPointerData(osgGA::GUIEventAdapter& source_event, osgGA::GUIEventAdapter& dest_event) { osgViewer::GraphicsWindow* gw = dynamic_cast(dest_event.getGraphicsContext()); if (!gw) return; float x = dest_event.getX(); float y = dest_event.getY(); bool invert_y = dest_event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; dest_event.addPointerData(new osgGA::PointerData(gw, x, 0, gw->getTraits()->width, y, 0, gw->getTraits()->height)); dest_event.setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); osg::Camera* camera = (source_event.getNumPointerData()>=2) ? dynamic_cast(source_event.getPointerData(1)->object.get()) : 0; osg::Viewport* viewport = camera ? camera->getViewport() : 0; if (!viewport) return; dest_event.addPointerData(new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0, (y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0)); // if camera isn't the master it must be a slave and could need reprojecting. if (camera!=getCamera()) { generateSlavePointerData(camera, dest_event); } } void Viewer::eventTraversal() { if (_done) return; double cutOffTime = _frameStamp->getReferenceTime(); double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // OSG_NOTICE<<"Viewer::frameEventTraversal()."<getCurrentEventState(); // get events from user Devices attached to Viewer. for(Devices::iterator eitr = _eventSources.begin(); eitr != _eventSources.end(); ++eitr) { osgGA::Device* es = eitr->get(); if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS) es->checkEvents(); // open question, will we need to reproject mouse coordinates into current view's coordinate frame as is down for GraphicsWindow provided events? // for now assume now and just get the events directly without any reprojection. es->getEventQueue()->takeEvents(events, cutOffTime); } // get events from all windows attached to Viewer. for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->checkEvents(); osgGA::EventQueue::Events gw_events; gw->getEventQueue()->takeEvents(gw_events, cutOffTime); osgGA::EventQueue::Events::iterator itr; for(itr = gw_events.begin(); itr != gw_events.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; event->setGraphicsContext(gw); switch(event->getEventType()) { case(osgGA::GUIEventAdapter::PUSH): case(osgGA::GUIEventAdapter::RELEASE): case(osgGA::GUIEventAdapter::DOUBLECLICK): case(osgGA::GUIEventAdapter::MOVE): case(osgGA::GUIEventAdapter::DRAG): { if (event->getEventType()!=osgGA::GUIEventAdapter::DRAG || eventState->getGraphicsContext()!=event->getGraphicsContext() || eventState->getNumPointerData()<2) { generatePointerData(*event); } else { reprojectPointerData(*eventState, *event); } eventState->copyPointerDataFrom(*event); break; } default: event->copyPointerDataFrom(*eventState); break; } events.push_back(event); } for(itr = gw_events.begin(); itr != gw_events.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::CLOSE_WINDOW): { bool wasThreading = areThreadsRunning(); if (wasThreading) stopThreading(); gw->close(); _currentContext = NULL; if (wasThreading) startThreading(); break; } default: break; } } } } // create a frame event for the new frame. { osg::ref_ptr event = _eventQueue->frame( getFrameStamp()->getReferenceTime() ); if (!eventState || eventState->getNumPointerData()<2) { generatePointerData(*event); } else { reprojectPointerData(*eventState, *event); } } // OSG_NOTICE<<"mouseEventState Xmin = "<getXmin()<<" Ymin="<getYmin()<<" xMax="<getXmax()<<" Ymax="<getYmax()<takeEvents(events, cutOffTime); // OSG_NOTICE<<"Events "<asGUIEventAdapter(); if (!event) continue; // ignore event if it's already been handled. if (event->getHandled()) continue; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): if (_keyEventSetsDone && event->getKey()==_keyEventSetsDone) _done = true; break; case(osgGA::GUIEventAdapter::QUIT_APPLICATION): if (_quitEventSetsDone) _done = true; break; default: break; } } } if (_done) return; if (_eventVisitor.valid() && getSceneData()) { _eventVisitor->setFrameStamp(getFrameStamp()); _eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; _eventVisitor->reset(); _eventVisitor->addEvent( event ); getSceneData()->accept(*_eventVisitor); // Do EventTraversal for slaves with their own subgraph for(unsigned int i=0; iaccept(*_eventVisitor); } } // call any camera event callbacks, but only traverse that callback, don't traverse its subgraph // leave that to the scene update traversal. osg::NodeVisitor::TraversalMode tm = _eventVisitor->getTraversalMode(); _eventVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE); if (_camera.valid() && _camera->getEventCallback()) _camera->accept(*_eventVisitor); for(unsigned int i=0; igetEventCallback()) { camera->accept(*_eventVisitor); } } _eventVisitor->setTraversalMode(tm); } } for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::Event* event = itr->get(); for(EventHandlers::iterator hitr = _eventHandlers.begin(); hitr != _eventHandlers.end(); ++hitr) { (*hitr)->handle( event, 0, _eventVisitor.get()); } } for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::Event* event = itr->get(); if (event && _cameraManipulator.valid()) { _cameraManipulator->handle( event, 0, _eventVisitor.get()); } } if (getViewerStats() && getViewerStats()->collectStats("event")) { double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // update current frames stats getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal begin time", beginEventTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal end time", endEventTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal time taken", endEventTraversal-beginEventTraversal); } } void Viewer::updateTraversal() { if (_done) return; double beginUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); _updateVisitor->reset(); _updateVisitor->setFrameStamp(getFrameStamp()); _updateVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); _scene->updateSceneGraph(*_updateVisitor); // if we have a shared state manager prune any unused entries if (osgDB::Registry::instance()->getSharedStateManager()) osgDB::Registry::instance()->getSharedStateManager()->prune(); // update the Registry object cache. osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(*getFrameStamp()); osgDB::Registry::instance()->removeExpiredObjectsInCache(*getFrameStamp()); if (_updateOperations.valid()) { _updateOperations->runOperations(this); } if (_incrementalCompileOperation.valid()) { // merge subgraphs that have been compiled by the incremental compiler operation. _incrementalCompileOperation->mergeCompiledSubgraphs(getFrameStamp()); } { // Do UpdateTraversal for slaves with their own subgraph for(unsigned int i=0; iaccept(*_updateVisitor); } } } { // call any camera update callbacks, but only traverse that callback, don't traverse its subgraph // leave that to the scene update traversal. osg::NodeVisitor::TraversalMode tm = _updateVisitor->getTraversalMode(); _updateVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE); if (_camera.valid() && _camera->getUpdateCallback()) _camera->accept(*_updateVisitor); for(unsigned int i=0; igetUpdateCallback()) { camera->accept(*_updateVisitor); } } _updateVisitor->setTraversalMode(tm); } if (_cameraManipulator.valid()) { setFusionDistance( getCameraManipulator()->getFusionDistanceMode(), getCameraManipulator()->getFusionDistanceValue() ); _cameraManipulator->updateCamera(*_camera); } updateSlaves(); if (getViewerStats() && getViewerStats()->collectStats("update")) { double endUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // update current frames stats getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal begin time", beginUpdateTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal end time", endUpdateTraversal); getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal time taken", endUpdateTraversal-beginUpdateTraversal); } } void Viewer::getScenes(Scenes& scenes, bool /*onlyValid*/) { scenes.clear(); scenes.push_back(_scene.get()); } void Viewer::getViews(Views& views, bool /*onlyValid*/) { views.clear(); views.push_back(this); } void Viewer::getAllThreads(Threads& threads, bool onlyActive) { threads.clear(); OperationThreads operationThreads; getOperationThreads(operationThreads); for(OperationThreads::iterator itr = operationThreads.begin(); itr != operationThreads.end(); ++itr) { threads.push_back(*itr); } if (_scene.valid()) { osgDB::DatabasePager* dp = _scene->getDatabasePager(); if (dp) { for(unsigned int i=0; igetNumDatabaseThreads(); ++i) { osgDB::DatabasePager::DatabaseThread* dt = dp->getDatabaseThread(i); if (!onlyActive || dt->isRunning()) { threads.push_back(dt); } } } } } void Viewer::getOperationThreads(OperationThreads& threads, bool onlyActive) { threads.clear(); Contexts contexts; getContexts(contexts); for(Contexts::iterator gcitr = contexts.begin(); gcitr != contexts.end(); ++gcitr) { osg::GraphicsContext* gc = *gcitr; if (gc->getGraphicsThread() && (!onlyActive || gc->getGraphicsThread()->isRunning()) ) { threads.push_back(gc->getGraphicsThread()); } } Cameras cameras; getCameras(cameras); for(Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { osg::Camera* camera = *citr; if (camera->getCameraThread() && (!onlyActive || camera->getCameraThread()->isRunning()) ) { threads.push_back(camera->getCameraThread()); } } } void Viewer::getContexts(Contexts& contexts, bool onlyValid) { typedef std::set ContextSet; ContextSet contextSet; contexts.clear(); if (_camera.valid() && _camera->getGraphicsContext() && (_camera->getGraphicsContext()->valid() || !onlyValid)) { contextSet.insert(_camera->getGraphicsContext()); contexts.push_back(_camera->getGraphicsContext()); } for(unsigned int i=0; igetGraphicsContext() : 0; if (sgc && (sgc->valid() || !onlyValid)) { if (contextSet.count(sgc)==0) { contextSet.insert(sgc); contexts.push_back(sgc); } } } } void Viewer::getCameras(Cameras& cameras, bool onlyActive) { cameras.clear(); if (_camera.valid() && (!onlyActive || (_camera->getGraphicsContext() && _camera->getGraphicsContext()->valid())) ) cameras.push_back(_camera.get()); for(Slaves::iterator itr = _slaves.begin(); itr != _slaves.end(); ++itr) { if (itr->_camera.valid() && (!onlyActive || (itr->_camera->getGraphicsContext() && itr->_camera->getGraphicsContext()->valid())) ) cameras.push_back(itr->_camera.get()); } } double Viewer::elapsedTime() { return osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); } void Viewer::getUsage(osg::ApplicationUsage& usage) const { if (_cameraManipulator.valid()) { _cameraManipulator->getUsage(usage); } for(EventHandlers::const_iterator hitr = _eventHandlers.begin(); hitr != _eventHandlers.end(); ++hitr) { (*hitr)->getUsage(usage); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/Renderer.cpp0000644000175000017500000010273313151044751024103 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; //#define DEBUG_MESSAGE OSG_NOTICE #define DEBUG_MESSAGE OSG_DEBUG OpenGLQuerySupport::OpenGLQuerySupport(): _extensions(0) { } class OSGVIEWER_EXPORT EXTQuerySupport : public OpenGLQuerySupport { public: EXTQuerySupport(); void checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t startTick); virtual void beginQuery(unsigned int frameNumber, osg::State* state); virtual void endQuery(osg::State* state); virtual void initialize(osg::State* state, osg::Timer_t startTick); protected: GLuint createQueryObject(); typedef std::pair QueryFrameNumberPair; typedef std::list QueryFrameNumberList; typedef std::vector QueryList; QueryFrameNumberList _queryFrameNumberList; QueryList _availableQueryObjects; double _previousQueryTime; }; EXTQuerySupport::EXTQuerySupport(): _previousQueryTime(0.0) { } void EXTQuerySupport::checkQuery(osg::Stats* stats, osg::State* /*state*/, osg::Timer_t startTick) { for(QueryFrameNumberList::iterator itr = _queryFrameNumberList.begin(); itr != _queryFrameNumberList.end(); ) { GLuint query = itr->first; GLint available = 0; _extensions->glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &available); if (available) { GLuint64 timeElapsed = 0; _extensions->glGetQueryObjectui64v(query, GL_QUERY_RESULT, &timeElapsed); double timeElapsedSeconds = double(timeElapsed)*1e-9; double currentTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); double estimatedEndTime = (_previousQueryTime + currentTime) * 0.5; double estimatedBeginTime = estimatedEndTime - timeElapsedSeconds; stats->setAttribute(itr->second, "GPU draw begin time", estimatedBeginTime); stats->setAttribute(itr->second, "GPU draw end time", estimatedEndTime); stats->setAttribute(itr->second, "GPU draw time taken", timeElapsedSeconds); itr = _queryFrameNumberList.erase(itr); _availableQueryObjects.push_back(query); } else { ++itr; } } _previousQueryTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); } GLuint EXTQuerySupport::createQueryObject() { if (_availableQueryObjects.empty()) { GLuint query; _extensions->glGenQueries(1, &query); return query; } else { GLuint query = _availableQueryObjects.back(); _availableQueryObjects.pop_back(); return query; } } void EXTQuerySupport::beginQuery(unsigned int frameNumber, osg::State* /*state*/) { GLuint query = createQueryObject(); _extensions->glBeginQuery(GL_TIME_ELAPSED, query); _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber)); } void EXTQuerySupport::endQuery(osg::State* /*state*/) { _extensions->glEndQuery(GL_TIME_ELAPSED); } void OpenGLQuerySupport::initialize(osg::State* state, osg::Timer_t /*startTick*/) { _extensions = state->get(); } void EXTQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) { OpenGLQuerySupport::initialize(state, startTick); _previousQueryTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); } class ARBQuerySupport : public OpenGLQuerySupport { public: virtual void checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t startTick); virtual void beginQuery(unsigned int frameNumber, osg::State* state); virtual void endQuery(osg::State* state); virtual void initialize(osg::State* state, osg::Timer_t startTick); protected: typedef std::pair QueryPair; struct ActiveQuery { ActiveQuery() : queries(0, 0), frameNumber(0) {} ActiveQuery(GLuint start_, GLuint end_, int frameNumber_) : queries(start_, end_), frameNumber(frameNumber_) { } ActiveQuery(const QueryPair& queries_, unsigned int frameNumber_) : queries(queries_), frameNumber(frameNumber_) { } QueryPair queries; unsigned int frameNumber; }; typedef std::list QueryFrameList; typedef std::vector QueryList; QueryFrameList _queryFrameList; QueryList _availableQueryObjects; }; void ARBQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) { OpenGLQuerySupport::initialize(state, startTick); } void ARBQuerySupport::beginQuery(unsigned int frameNumber, osg::State* /*state*/) { QueryPair query; if (_availableQueryObjects.empty()) { _extensions->glGenQueries(1, &query.first); _extensions->glGenQueries(1, &query.second); } else { query = _availableQueryObjects.back(); _availableQueryObjects.pop_back(); } _extensions->glQueryCounter(query.first, GL_TIMESTAMP); _queryFrameList.push_back(ActiveQuery(query, frameNumber)); } void ARBQuerySupport::endQuery(osg::State* /*state*/) { _extensions->glQueryCounter(_queryFrameList.back().queries.second, GL_TIMESTAMP); } void ARBQuerySupport::checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t /*startTick*/) { for(QueryFrameList::iterator itr = _queryFrameList.begin(); itr != _queryFrameList.end(); ) { GLint available = 0; // If the end query is available, the begin query must be too. _extensions->glGetQueryObjectiv(itr->queries.second, GL_QUERY_RESULT_AVAILABLE, &available); if (available) { QueryPair queries = itr->queries; GLuint64 beginTimestamp = 0; GLuint64 endTimestamp = 0; _extensions->glGetQueryObjectui64v(queries.first, GL_QUERY_RESULT, &beginTimestamp); _extensions->glGetQueryObjectui64v(queries.second, GL_QUERY_RESULT, &endTimestamp); GLuint64 gpuTimestamp = state->getGpuTimestamp(); // Have any of the timestamps wrapped around? int tbits = state->getTimestampBits(); if (tbits < 64) { // If the high bits on any of the timestamp bits are // different then the counters may have wrapped. const int hiShift = (tbits - 1); const GLuint64 one = 1; const GLuint64 hiMask = one << hiShift; const GLuint64 sum = (beginTimestamp >> hiShift) + (endTimestamp >> hiShift) + (gpuTimestamp >> hiShift); if (sum == 1 || sum == 2) { const GLuint64 wrapAdd = one << tbits; // Counter wrapped between begin and end? if (beginTimestamp > endTimestamp) { endTimestamp += wrapAdd; } else if (gpuTimestamp < beginTimestamp && beginTimestamp - gpuTimestamp > (hiMask >> 1)) { gpuTimestamp += wrapAdd; } else if (endTimestamp < gpuTimestamp && gpuTimestamp - endTimestamp > (hiMask >> 1)) { beginTimestamp += wrapAdd; endTimestamp += wrapAdd; } } } GLuint64 timeElapsed = endTimestamp - beginTimestamp; double timeElapsedSeconds = double(timeElapsed)*1e-9; double gpuTick = state->getGpuTime(); double beginTime = 0.0; double endTime = 0.0; if (beginTimestamp > gpuTimestamp) beginTime = gpuTick + double(beginTimestamp - gpuTimestamp) * 1e-9; else beginTime = gpuTick - double(gpuTimestamp - beginTimestamp) * 1e-9; if (endTimestamp > gpuTimestamp) endTime = gpuTick + double(endTimestamp - gpuTimestamp) * 1e-9; else endTime = gpuTick - double(gpuTimestamp - endTimestamp) * 1e-9; stats->setAttribute(itr->frameNumber, "GPU draw begin time", beginTime); stats->setAttribute(itr->frameNumber, "GPU draw end time", endTime); stats->setAttribute(itr->frameNumber, "GPU draw time taken", timeElapsedSeconds); itr = _queryFrameList.erase(itr); _availableQueryObjects.push_back(queries); } else { ++itr; } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // ThreadSafeQueue Renderer::ThreadSafeQueue::ThreadSafeQueue() : _isReleased(false) { } Renderer::ThreadSafeQueue::~ThreadSafeQueue() { } void Renderer::ThreadSafeQueue::release() { OpenThreads::ScopedLock lock(_mutex); _isReleased = true; _cond.broadcast(); } void Renderer::ThreadSafeQueue::reset() { OpenThreads::ScopedLock lock(_mutex); _queue.clear(); _isReleased = false; } osgUtil::SceneView* Renderer::ThreadSafeQueue::takeFront() { OpenThreads::ScopedLock lock(_mutex); // Loop in case there are spurious wakeups from the condition wait. while (true) { // If the queue has been released but nothing is enqueued, // just return. This prevents a deadlock when threading is // restarted. if (_isReleased) { if (!_queue.empty()) { osgUtil::SceneView* front = _queue.front(); _queue.pop_front(); if (_queue.empty()) _isReleased = false; return front; } return 0; } _cond.wait(&_mutex); } return 0; // Can't happen } void Renderer::ThreadSafeQueue::add(osgUtil::SceneView* sv) { OpenThreads::ScopedLock lock(_mutex); _queue.push_back(sv); _isReleased = true; _cond.broadcast(); } static OpenThreads::ReentrantMutex s_drawSerializerMutex; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // Renderer Renderer::Renderer(osg::Camera* camera): osg::Referenced(true), osg::GraphicsOperation("Renderer",true), _camera(camera), _done(false), _graphicsThreadDoesCull(true), _compileOnNextDraw(true), _serializeDraw(false), _initialized(false), _startTick(0) { DEBUG_MESSAGE<<"Render::Render() "<setFrameStamp(new osg::FrameStamp()); _sceneView[1]->setFrameStamp(new osg::FrameStamp()); osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : camera; osg::StateSet* global_stateset = 0; osg::StateSet* secondary_stateset = 0; if (_camera != masterCamera) { global_stateset = masterCamera->getOrCreateStateSet(); secondary_stateset = _camera->getStateSet(); } else { global_stateset = _camera->getOrCreateStateSet(); } osgViewer::View* view = dynamic_cast(_camera->getView()); osgViewer::ViewerBase* viewer = view ? view->getViewerBase() : 0; osgUtil::IncrementalCompileOperation* ico = viewer ? viewer->getIncrementalCompileOperation() : 0; bool automaticFlush = (ico==NULL); osg::DisplaySettings* ds = _camera->getDisplaySettings() ? _camera->getDisplaySettings() : ((view && view->getDisplaySettings()) ? view->getDisplaySettings() : osg::DisplaySettings::instance().get()); _serializeDraw = ds ? ds->getSerializeDrawDispatch() : false; unsigned int sceneViewOptions = osgUtil::SceneView::HEADLIGHT; if (view) { switch(view->getLightingMode()) { case(osg::View::NO_LIGHT): sceneViewOptions = 0; break; case(osg::View::SKY_LIGHT): sceneViewOptions = osgUtil::SceneView::SKY_LIGHT; break; case(osg::View::HEADLIGHT): sceneViewOptions = osgUtil::SceneView::HEADLIGHT; break; } } _sceneView[0]->setAutomaticFlush(automaticFlush); _sceneView[0]->setGlobalStateSet(global_stateset); _sceneView[0]->setSecondaryStateSet(secondary_stateset); _sceneView[1]->setAutomaticFlush(automaticFlush); _sceneView[1]->setGlobalStateSet(global_stateset); _sceneView[1]->setSecondaryStateSet(secondary_stateset); _sceneView[0]->setDefaults(sceneViewOptions); _sceneView[1]->setDefaults(sceneViewOptions); if (ds->getUseSceneViewForStereoHint()) { _sceneView[0]->setDisplaySettings(ds); _sceneView[1]->setDisplaySettings(ds); } else { _sceneView[0]->setResetColorMaskToAllOn(false); _sceneView[1]->setResetColorMaskToAllOn(false); } _sceneView[0]->setCamera(_camera.get(), false); _sceneView[1]->setCamera(_camera.get(), false); { // assign CullVisitor::Identifier so that the double buffering of SceneView doesn't interfer // with code that requires a consistent knowledge and which effective cull traversal to taking place osg::ref_ptr leftEyeIdentifier = new osgUtil::CullVisitor::Identifier(); osg::ref_ptr rightEyeIdentifier = new osgUtil::CullVisitor::Identifier(); _sceneView[0]->getCullVisitor()->setIdentifier(leftEyeIdentifier.get()); _sceneView[0]->setCullVisitorLeft(_sceneView[0]->getCullVisitor()->clone()); _sceneView[0]->getCullVisitorLeft()->setIdentifier(leftEyeIdentifier.get()); _sceneView[0]->setCullVisitorRight(_sceneView[0]->getCullVisitor()->clone()); _sceneView[0]->getCullVisitorRight()->setIdentifier(rightEyeIdentifier.get()); _sceneView[1]->getCullVisitor()->setIdentifier(leftEyeIdentifier.get()); _sceneView[1]->setCullVisitorLeft(_sceneView[1]->getCullVisitor()->clone()); _sceneView[1]->getCullVisitorLeft()->setIdentifier(leftEyeIdentifier.get()); _sceneView[1]->setCullVisitorRight(_sceneView[1]->getCullVisitor()->clone()); _sceneView[1]->getCullVisitorRight()->setIdentifier(rightEyeIdentifier.get()); } // lock the mutex for the current cull SceneView to // prevent the draw traversal from reading from it before the cull traversal has been completed. _availableQueue.add(_sceneView[0].get()); _availableQueue.add(_sceneView[1].get()); DEBUG_MESSAGE<<"_availableQueue.size()="<<_availableQueue._queue.size()<get(); if (ext->isARBTimerQuerySupported && state->getTimestampBits() > 0) _querySupport = new ARBQuerySupport(); else if (ext->isTimerQuerySupported) _querySupport = new EXTQuerySupport(); if (_querySupport.valid()) _querySupport->initialize(state, _startTick); } } void Renderer::setGraphicsThreadDoesCull(bool flag) { if (_graphicsThreadDoesCull==flag) return; _graphicsThreadDoesCull = flag; } void Renderer::updateSceneView(osgUtil::SceneView* sceneView) { osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : _camera.get(); osg::StateSet* global_stateset = 0; osg::StateSet* secondary_stateset = 0; if (_camera != masterCamera) { global_stateset = masterCamera->getOrCreateStateSet(); secondary_stateset = _camera->getStateSet(); } else { global_stateset = _camera->getOrCreateStateSet(); } if (sceneView->getGlobalStateSet()!=global_stateset) { sceneView->setGlobalStateSet(global_stateset); } if (sceneView->getSecondaryStateSet()!=secondary_stateset) { sceneView->setSecondaryStateSet(secondary_stateset); } osg::GraphicsContext* context = _camera->getGraphicsContext(); osg::State* state = context ? context->getState() : 0; if (sceneView->getState()!=state) { sceneView->setState(state); } osgViewer::View* view = dynamic_cast(_camera->getView()); osgViewer::ViewerBase* viewer = view ? view->getViewerBase() : 0; osgUtil::IncrementalCompileOperation* ico = viewer ? viewer->getIncrementalCompileOperation() : 0; bool automaticFlush = (ico==NULL); sceneView->setAutomaticFlush(automaticFlush); osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0; sceneView->getCullVisitor()->setDatabaseRequestHandler(databasePager); osgDB::ImagePager* imagePager = view ? view->getImagePager() : 0; sceneView->getCullVisitor()->setImageRequestHandler(imagePager); if (view && view->getFrameStamp()) { (*const_cast(sceneView->getFrameStamp())) = *(view->getFrameStamp()); } else if (state->getFrameStamp()) { (*const_cast(sceneView->getFrameStamp())) = *(state->getFrameStamp()); } osg::DisplaySettings* ds = _camera->getDisplaySettings() ? _camera->getDisplaySettings() : ((view &&view->getDisplaySettings()) ? view->getDisplaySettings() : osg::DisplaySettings::instance().get()); if (ds->getUseSceneViewForStereoHint()) { sceneView->setDisplaySettings(ds); } if (view) { _startTick = view->getStartTick(); if (state) state->setStartTick(_startTick); } } void Renderer::compile() { DEBUG_MESSAGE<<"Renderer::compile()"<getState()->checkGLErrors("Before Renderer::compile"); if (sceneView->getSceneData()) { osgUtil::GLObjectsVisitor glov; glov.setState(sceneView->getState()); sceneView->getSceneData()->accept(glov); } sceneView->getState()->checkGLErrors("After Renderer::compile"); } static void collectSceneViewStats(unsigned int frameNumber, osgUtil::SceneView* sceneView, osg::Stats* stats) { osgUtil::Statistics sceneStats; sceneView->getStats(sceneStats); stats->setAttribute(frameNumber, "Visible vertex count", static_cast(sceneStats._vertexCount)); stats->setAttribute(frameNumber, "Visible number of drawables", static_cast(sceneStats.numDrawables)); stats->setAttribute(frameNumber, "Visible number of fast drawables", static_cast(sceneStats.numFastDrawables)); stats->setAttribute(frameNumber, "Visible number of lights", static_cast(sceneStats.nlights)); stats->setAttribute(frameNumber, "Visible number of render bins", static_cast(sceneStats.nbins)); stats->setAttribute(frameNumber, "Visible depth", static_cast(sceneStats.depth)); stats->setAttribute(frameNumber, "Number of StateGraphs", static_cast(sceneStats.numStateGraphs)); stats->setAttribute(frameNumber, "Visible number of impostors", static_cast(sceneStats.nimpostor)); stats->setAttribute(frameNumber, "Number of ordered leaves", static_cast(sceneStats.numOrderedLeaves)); unsigned int totalNumPrimitiveSets = 0; const osgUtil::Statistics::PrimitiveValueMap& pvm = sceneStats.getPrimitiveValueMap(); for(osgUtil::Statistics::PrimitiveValueMap::const_iterator pvm_itr = pvm.begin(); pvm_itr != pvm.end(); ++pvm_itr) { totalNumPrimitiveSets += pvm_itr->second.first; } stats->setAttribute(frameNumber, "Visible number of PrimitiveSets", static_cast(totalNumPrimitiveSets)); osgUtil::Statistics::PrimitiveCountMap& pcm = sceneStats.getPrimitiveCountMap(); stats->setAttribute(frameNumber, "Visible number of GL_POINTS", static_cast(pcm[GL_POINTS])); stats->setAttribute(frameNumber, "Visible number of GL_LINES", static_cast(pcm[GL_LINES])); stats->setAttribute(frameNumber, "Visible number of GL_LINE_STRIP", static_cast(pcm[GL_LINE_STRIP])); stats->setAttribute(frameNumber, "Visible number of GL_LINE_LOOP", static_cast(pcm[GL_LINE_LOOP])); stats->setAttribute(frameNumber, "Visible number of GL_TRIANGLES", static_cast(pcm[GL_TRIANGLES])); stats->setAttribute(frameNumber, "Visible number of GL_TRIANGLE_STRIP", static_cast(pcm[GL_TRIANGLE_STRIP])); stats->setAttribute(frameNumber, "Visible number of GL_TRIANGLE_FAN", static_cast(pcm[GL_TRIANGLE_FAN])); stats->setAttribute(frameNumber, "Visible number of GL_QUADS", static_cast(pcm[GL_QUADS])); stats->setAttribute(frameNumber, "Visible number of GL_QUAD_STRIP", static_cast(pcm[GL_QUAD_STRIP])); stats->setAttribute(frameNumber, "Visible number of GL_POLYGON", static_cast(pcm[GL_POLYGON])); } void Renderer::cull() { DEBUG_MESSAGE<<"cull()"<(sceneView->getCamera()->getView()); if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue()); osg::Stats* stats = sceneView->getCamera()->getStats(); const osg::FrameStamp* fs = sceneView->getFrameStamp(); unsigned int frameNumber = fs ? fs->getFrameNumber() : 0; // do cull traversal osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); sceneView->inheritCullSettings(*(sceneView->getCamera())); sceneView->cull(); osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); #if 0 osg::State* state = sceneView->getState(); if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { // OSG_NOTICE<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); } #endif if (stats && stats->collectStats("rendering")) { DEBUG_MESSAGE<<"Collecting rendering stats"<setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick)); stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick)); } if (stats && stats->collectStats("scene")) { collectSceneViewStats(frameNumber, sceneView, stats); } _drawQueue.add(sceneView); } DEBUG_MESSAGE<<"end cull() "<tick(); osgUtil::SceneView* sceneView = _drawQueue.takeFront(); DEBUG_MESSAGE<<"draw() got SceneView "<collateReferencesToDependentCameras(); if (_compileOnNextDraw) { compile(); } // OSG_NOTICE<<"Drawing buffer "<<_currentDraw<getCamera()->getStats(); osg::State* state = sceneView->getState(); unsigned int frameNumber = sceneView->getFrameStamp()->getFrameNumber(); if (!_initialized) { initialize(state); } state->setDynamicObjectCount(sceneView->getDynamicObjectCount()); if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { // OSG_NOTICE<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); } bool acquireGPUStats = stats && _querySupport && stats->collectStats("gpu"); if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); } // do draw traversal if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); _querySupport->beginQuery(frameNumber, state); } osg::Timer_t beforeDrawTick; if (_serializeDraw) { OpenThreads::ScopedLock lock(s_drawSerializerMutex); beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } else { beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } _availableQueue.add(sceneView); if (acquireGPUStats) { _querySupport->endQuery(state); _querySupport->checkQuery(stats, state, _startTick); } //glFlush(); osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); // OSG_NOTICE<<"Time wait for draw = "<delta_m(startDrawTick, beforeDrawTick)<setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeDrawTick)); stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick)); stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(beforeDrawTick, afterDrawTick)); } sceneView->clearReferencesToDependentCameras(); } DEBUG_MESSAGE<<"end draw() "<(_camera->getView()); // OSG_NOTICE<<"RenderingOperation"<setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue()); osg::Stats* stats = sceneView->getCamera()->getStats(); osg::State* state = sceneView->getState(); const osg::FrameStamp* fs = sceneView->getFrameStamp(); unsigned int frameNumber = fs ? fs->getFrameNumber() : 0; if (!_initialized) { initialize(state); } bool acquireGPUStats = stats && _querySupport && stats->collectStats("gpu"); if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); } // do cull traversal osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); sceneView->inheritCullSettings(*(sceneView->getCamera())); sceneView->cull(); osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); if (stats && stats->collectStats("scene")) { collectSceneViewStats(frameNumber, sceneView, stats); } #if 0 if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { state->getDynamicObjectRenderingCompletedCallback()->completed(state); } #endif // do draw traversal if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); _querySupport->beginQuery(frameNumber, state); } osg::Timer_t beforeDrawTick; if (_serializeDraw) { OpenThreads::ScopedLock lock(s_drawSerializerMutex); beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } else { beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } if (acquireGPUStats) { _querySupport->endQuery(state); _querySupport->checkQuery(stats, state, _startTick); } osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); if (stats && stats->collectStats("rendering")) { DEBUG_MESSAGE<<"Collecting rendering stats"<setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick)); stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick)); stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeDrawTick)); stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick)); stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(beforeDrawTick, afterDrawTick)); } DEBUG_MESSAGE<<"end cull_draw() "<(object); if (context) operator()(context); osg::Camera* camera = dynamic_cast(object); if (camera) cull(); } void Renderer::operator () (osg::GraphicsContext* /*context*/) { if (_graphicsThreadDoesCull) { cull_draw(); } else { draw(); } } void Renderer::release() { OSG_INFO<<"Renderer::release()"<getRenderStage() : 0; if (rs) rs->setCameraRequiresSetUp(flag); rs = sv ? sv->getRenderStageLeft() : 0; if (rs) rs->setCameraRequiresSetUp(flag); rs = sv ? sv->getRenderStageRight() : 0; if (rs) rs->setCameraRequiresSetUp(flag); } } bool Renderer::getCameraRequiresSetUp() const { bool result = false; for (int i = 0; i < 2; ++i) { const osgUtil::SceneView* sv = getSceneView(i); const osgUtil::RenderStage* rs = sv ? sv->getRenderStage() : 0; if (rs) result = result || rs->getCameraRequiresSetUp(); rs = sv ? sv->getRenderStageLeft() : 0; if (rs) result = result || rs->getCameraRequiresSetUp(); rs = sv ? sv->getRenderStageRight() : 0; if (rs) result = result || rs->getCameraRequiresSetUp(); } return result; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/PixelBufferCarbon.cpp0000644000175000017500000001276513151044751025702 0ustar albertoalberto/* * PixelBufferCarbon.cpp * OpenSceneGraph * * Created by Stephan Huber on 27.06.07. * Copyright 2007 __MyCompanyName__. All rights reserved. * */ #if defined (__APPLE__) && (!__LP64__) #include #include #include #include #include using namespace osgViewer; /** creates a pixelformat from a Trait */ AGLPixelFormat PixelBufferCarbon::createPixelFormat(osg::GraphicsContext::Traits* traits) { std::vector attributes; attributes.push_back(AGL_NO_RECOVERY); attributes.push_back(AGL_RGBA); if (!traits->pbuffer) attributes.push_back(AGL_COMPLIANT); else attributes.push_back(AGL_CLOSEST_POLICY); if (traits->doubleBuffer) attributes.push_back(AGL_DOUBLEBUFFER); if (traits->quadBufferStereo) attributes.push_back(AGL_STEREO); attributes.push_back(AGL_RED_SIZE); attributes.push_back(traits->red); attributes.push_back(AGL_GREEN_SIZE); attributes.push_back(traits->green); attributes.push_back(AGL_BLUE_SIZE); attributes.push_back(traits->blue); attributes.push_back(AGL_DEPTH_SIZE); attributes.push_back(traits->depth); if (traits->alpha) { attributes.push_back(AGL_ALPHA_SIZE); attributes.push_back(traits->alpha); } if (traits->stencil) { attributes.push_back(AGL_STENCIL_SIZE); attributes.push_back(traits->stencil); } // TODO // missing accumulation-buffer-stuff #if defined(AGL_SAMPLE_BUFFERS_ARB) && defined (AGL_SAMPLES_ARB) if (traits->sampleBuffers) { attributes.push_back(AGL_SAMPLE_BUFFERS_ARB); attributes.push_back(traits->sampleBuffers); } if (traits->sampleBuffers) { attributes.push_back(AGL_SAMPLES_ARB); attributes.push_back(traits->samples); } #endif attributes.push_back(AGL_NONE); return aglChoosePixelFormat(NULL, 0, &(attributes.front())); } void PixelBufferCarbon::init() { _context = NULL; _pixelformat = PixelBufferCarbon::createPixelFormat(_traits.get()); if (!_pixelformat) OSG_WARN << "PixelBufferCarbon::init could not create a valid pixelformat" << std::endl; _valid = (_pixelformat != NULL); } /** This is the class we need to create for pbuffers, note its not a GraphicsWindow as it won't need any of the event handling and window mapping facilities.*/ /** Realise the GraphicsContext implementation, * Pure virtual - must be implemented by concrate implementations of GraphicsContext. */ bool PixelBufferCarbon::realizeImplementation() { if (!_valid) { OSG_WARN << "PixelBufferCarbon::realizeImplementation() aglChoosePixelFormat failed! " << aglErrorString(aglGetError()) << std::endl; return false; } AGLContext sharedContext = NULL; // get any shared AGL contexts GraphicsHandleCarbon* graphicsHandleCarbon = dynamic_cast(_traits->sharedContext.get()); if (graphicsHandleCarbon) { sharedContext = graphicsHandleCarbon->getAGLContext(); } _context = aglCreateContext (_pixelformat, sharedContext); if (!_context) { OSG_WARN << "PixelBufferCarbon::realizeImplementation() aglCreateContext failed! " << aglErrorString(aglGetError()) << std::endl; return false; } _realized = aglCreatePBuffer (_traits->width, _traits->height, _traits->target, GL_RGBA, _traits->level, &(_pbuffer)); if (!_realized) { OSG_WARN << "PixelBufferCarbon::realizeImplementation() aglCreatePBuffer failed! " << aglErrorString(aglGetError()) << std::endl; } makeCurrentImplementation(); _realized = aglSetPBuffer(_context, _pbuffer, _traits->face, _traits->level, 0); if (!_realized) { OSG_WARN << "PixelBufferCarbon::realizeImplementation() aglSetPBuffer failed! " << aglErrorString(aglGetError()) << std::endl; } return _realized; } void PixelBufferCarbon::closeImplementation() { if (_pbuffer) aglDestroyPBuffer(_pbuffer); if (_context) aglDestroyContext(_context); if (_pixelformat) aglDestroyPixelFormat(_pixelformat); _pbuffer = NULL; _context = NULL; _pixelformat = NULL; _valid = _realized = false; } /** Make this graphics context current implementation. * Pure virtual - must be implemented by concrate implementations of GraphicsContext. */ bool PixelBufferCarbon::makeCurrentImplementation() { return (_realized) ? (aglSetCurrentContext(_context) == GL_TRUE) : false; } /** Make this graphics context current with specified read context implementation. * Pure virtual - must be implemented by concrate implementations of GraphicsContext. */ bool PixelBufferCarbon::makeContextCurrentImplementation(GraphicsContext* /*readContext*/) { return makeCurrentImplementation(); } /** Release the graphics context.*/ bool PixelBufferCarbon::releaseContextImplementation() { return (aglSetCurrentContext(NULL) == GL_TRUE); } /** Pure virtual, Bind the graphics context to associated texture implementation. * Pure virtual - must be implemented by concrate implementations of GraphicsContext. */ void PixelBufferCarbon::bindPBufferToTextureImplementation( GLenum buffer ){ OSG_NOTICE<<"GraphicsWindow::void bindPBufferToTextureImplementation(..) not implemented."< #include #include #include //#define USE_DARWIN_COCOA_IMPLEMENTATION 1 //#define USE_DARWIN_CARBON_IMPLEMENTATION 1 #ifdef __OBJC__ @class MenubarToggler; #else class MenubarToggler; #endif namespace osgDarwin { /** the MenubarController class checks all open windows if they intersect with the menubar / dock and hide the menubar/dock if necessary */ class MenubarController : public osg::Referenced { public: class WindowAdapter : public osg::Referenced { public: WindowAdapter() : osg::Referenced() {} virtual bool valid() = 0; virtual void getWindowBounds(CGRect& rect) = 0; virtual osgViewer::GraphicsWindow* getWindow() = 0; protected: virtual ~WindowAdapter() {} }; MenubarController(); static MenubarController* instance(); void attachWindow(WindowAdapter* win); void update(); void detachWindow(osgViewer::GraphicsWindow* win); void setDisplaySettings(osg::DisplaySettings* display_settings); protected: ~MenubarController(); private: typedef std::list< osg::ref_ptr< WindowAdapter > > WindowList; WindowList _list; bool _menubarShown; CGRect _availRect; CGRect _mainScreenBounds; OpenThreads::Mutex _mutex; MenubarToggler* _toggler; }; struct DarwinWindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface { public: DarwinWindowingSystemInterface(); /** dtor */ ~DarwinWindowingSystemInterface(); /** @return a CGDirectDisplayID for a ScreenIdentifier */ CGDirectDisplayID getDisplayID(const osg::GraphicsContext::ScreenIdentifier& si); /** @return count of attached screens */ virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si) ; virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution); virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList); virtual bool setScreenSettings (const osg::GraphicsContext::ScreenIdentifier & si, const osg::GraphicsContext::ScreenSettings & settings); /** return the top left coord of a specific screen in global screen space */ void getScreenTopLeft(const osg::GraphicsContext::ScreenIdentifier& si, int& x, int& y); /** returns screen-ndx containing rect x,y,w,h */ unsigned int getScreenContaining(int x, int y, int w, int h); virtual void setDisplaySettings(osg::DisplaySettings* display_settings) { MenubarController::instance()->setDisplaySettings(display_settings); } protected: virtual void _init(); template osg::GraphicsContext* createGraphicsContextImplementation(osg::GraphicsContext::Traits* traits) { if (traits->pbuffer) { osg::ref_ptr pbuffer = new PixelBufferImplementation(traits); if (pbuffer->valid()) return pbuffer.release(); else return 0; } else { osg::ref_ptr window = new GraphicsWindowImplementation(traits); if (window->valid()) return window.release(); else return 0; } } protected: bool _initialized; CGDisplayCount _displayCount; CGDirectDisplayID* _displayIds; }; template struct RegisterWindowingSystemInterfaceProxy { RegisterWindowingSystemInterfaceProxy() { osg::GraphicsContext::setWindowingSystemInterface(new WSI); } ~RegisterWindowingSystemInterfaceProxy() { if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } osg::GraphicsContext::setWindowingSystemInterface(0); } }; } #endif #endif // __APPLE__ OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgViewer/StatsHandler.cpp0000644000175000017500000021202113151044751024721 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include namespace osgViewer { #if (!defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)) #define GLSL_VERSION_STR "330 core" #else #define GLSL_VERSION_STR "300 es" #endif StatsHandler::StatsHandler(): _keyEventTogglesOnScreenStats('s'), _keyEventPrintsOutStats('S'), _statsType(NO_STATS), _initialized(false), _threadingModel(ViewerBase::SingleThreaded), _frameRateChildNum(0), _viewerChildNum(0), _cameraSceneChildNum(0), _viewerSceneChildNum(0), _numBlocks(8), _blockMultiplier(10000.0), _statsWidth(1280.0f), _statsHeight(1024.0f), _font("fonts/arial.ttf"), _startBlocks(150.0f), _leftPos(10.0f), _characterSize(20.0f), _lineHeight(1.5f) { OSG_INFO<<"StatsHandler::StatsHandler()"<getOrCreateStateSet()->setGlobalDefaults(); _camera->setRenderer(new Renderer(_camera.get())); _camera->setProjectionResizePolicy(osg::Camera::FIXED); #if defined(OSG_GL3_AVAILABLE) || defined(OSG_GLES3_AVAILABLE) { OSG_NOTICE<<"StatsHandler::StatsHandler() Setting up GL3 compatible shaders"< program = new osg::Program; program->addShader(new osg::Shader(osg::Shader::VERTEX, gl3_StatsVertexShader)); program->addShader(new osg::Shader(osg::Shader::FRAGMENT, gl3_StatsFragmentShader)); _camera->getOrCreateStateSet()->setAttributeAndModes(program.get()); } #elif defined(OSG_GL2_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) { OSG_NOTICE<<"StatsHandler::StatsHandler() Setting up GL2 compatible shaders"< program = new osg::Program; program->addShader(new osg::Shader(osg::Shader::VERTEX, gl2_StatsVertexShader)); program->addShader(new osg::Shader(osg::Shader::FRAGMENT, gl2_StatsFragmentShader)); _camera->getOrCreateStateSet()->setAttributeAndModes(program.get()); } #else { OSG_INFO<<"StatsHandler::StatsHandler() Fixed pipeline"<getCameras(cameras); } bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { osgViewer::View* myview = dynamic_cast(&aa); if (!myview) return false; osgViewer::ViewerBase* viewer = myview->getViewerBase(); if (viewer && _threadingModelText.valid() && viewer->getThreadingModel()!=_threadingModel) { _threadingModel = viewer->getThreadingModel(); updateThreadingModelText(); } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): { if (ea.getKey()==_keyEventTogglesOnScreenStats) { if (viewer && viewer->getViewerStats()) { if (!_initialized) { setUpHUDCamera(viewer); setUpScene(viewer); } ++_statsType; if (_statsType==LAST) _statsType = NO_STATS; osgViewer::ViewerBase::Cameras cameras; collectWhichCamerasToRenderStatsFor(viewer, cameras); switch(_statsType) { case(NO_STATS): { viewer->getViewerStats()->collectStats("frame_rate",false); viewer->getViewerStats()->collectStats("event",false); viewer->getViewerStats()->collectStats("update",false); for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin(); itr != cameras.end(); ++itr) { osg::Stats* stats = (*itr)->getStats(); if (stats) { stats->collectStats("rendering",false); stats->collectStats("gpu",false); stats->collectStats("scene",false); } } viewer->getViewerStats()->collectStats("scene",false); _camera->setNodeMask(0x0); _switch->setAllChildrenOff(); break; } case(FRAME_RATE): { viewer->getViewerStats()->collectStats("frame_rate",true); _camera->setNodeMask(0xffffffff); _switch->setValue(_frameRateChildNum, true); break; } case(VIEWER_STATS): { ViewerBase::Scenes scenes; viewer->getScenes(scenes); for(ViewerBase::Scenes::iterator itr = scenes.begin(); itr != scenes.end(); ++itr) { Scene* scene = *itr; osgDB::DatabasePager* dp = scene->getDatabasePager(); if (dp && dp->isRunning()) { dp->resetStats(); } } viewer->getViewerStats()->collectStats("event",true); viewer->getViewerStats()->collectStats("update",true); for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin(); itr != cameras.end(); ++itr) { if ((*itr)->getStats()) (*itr)->getStats()->collectStats("rendering",true); if ((*itr)->getStats()) (*itr)->getStats()->collectStats("gpu",true); } _camera->setNodeMask(0xffffffff); _switch->setValue(_viewerChildNum, true); break; } case(CAMERA_SCENE_STATS): { _camera->setNodeMask(0xffffffff); _switch->setValue(_cameraSceneChildNum, true); for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin(); itr != cameras.end(); ++itr) { osg::Stats* stats = (*itr)->getStats(); if (stats) { stats->collectStats("scene",true); } } break; } case(VIEWER_SCENE_STATS): { _camera->setNodeMask(0xffffffff); _switch->setValue(_viewerSceneChildNum, true); viewer->getViewerStats()->collectStats("scene",true); break; } default: break; } aa.requestRedraw(); } return true; } if (ea.getKey()==_keyEventPrintsOutStats) { if (viewer && viewer->getViewerStats()) { OSG_NOTICE< StatsList; StatsList statsList; statsList.push_back(viewer->getViewerStats()); osgViewer::ViewerBase::Contexts contexts; viewer->getContexts(contexts); for(osgViewer::ViewerBase::Contexts::iterator gcitr = contexts.begin(); gcitr != contexts.end(); ++gcitr) { osg::GraphicsContext::Cameras& cameras = (*gcitr)->getCameras(); for(osg::GraphicsContext::Cameras::iterator itr = cameras.begin(); itr != cameras.end(); ++itr) { if ((*itr)->getStats()) { statsList.push_back((*itr)->getStats()); } } } for(unsigned int i = viewer->getViewerStats()->getEarliestFrameNumber(); i< viewer->getViewerStats()->getLatestFrameNumber(); ++i) { for(StatsList::iterator itr = statsList.begin(); itr != statsList.end(); ++itr) { if (itr==statsList.begin()) (*itr)->report(osg::notify(osg::NOTICE), i); else (*itr)->report(osg::notify(osg::NOTICE), i, " "); } OSG_NOTICE<setText("ThreadingModel: SingleThreaded"); break; case(osgViewer::Viewer::CullDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullDrawThreadPerContext"); break; case(osgViewer::Viewer::DrawThreadPerContext): _threadingModelText->setText("ThreadingModel: DrawThreadPerContext"); break; case(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullThreadPerCameraDrawThreadPerContext"); break; case(osgViewer::Viewer::AutomaticSelection): _threadingModelText->setText("ThreadingModel: AutomaticSelection"); break; default: _threadingModelText->setText("ThreadingModel: unknown"); break; } } void StatsHandler::reset() { _initialized = false; _camera->setGraphicsContext(0); _camera->removeChildren( 0, _camera->getNumChildren() ); } void StatsHandler::addUserStatsLine(const std::string& label, const osg::Vec4& textColor, const osg::Vec4& barColor, const std::string& timeTakenName, float multiplier, bool average, bool averageInInverseSpace, const std::string& beginTimeName, const std::string& endTimeName, float maxValue) { _userStatsLines.push_back(UserStatsLine(label, textColor, barColor, timeTakenName, multiplier, average, averageInInverseSpace, beginTimeName, endTimeName, maxValue)); reset(); // Rebuild the stats display with the new user stats line. } void StatsHandler::removeUserStatsLine(const std::string& label) { // Hopefully the labels are unique... This could be enforced. for (unsigned int i = 0; i < _userStatsLines.size(); ++i) { if (_userStatsLines[i].label == label) { _userStatsLines.erase(_userStatsLines.begin() + i); reset(); // Rebuild the stats display without the removed user stats line. break; } } } void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer) { // Try GraphicsWindow first so we're likely to get the main viewer window osg::GraphicsContext* context = dynamic_cast(_camera->getGraphicsContext()); if (!context) { osgViewer::Viewer::Windows windows; viewer->getWindows(windows); if (!windows.empty()) context = windows.front(); else { // No GraphicsWindows were found, so let's try to find a GraphicsContext context = _camera->getGraphicsContext(); if (!context) { osgViewer::Viewer::Contexts contexts; viewer->getContexts(contexts); if (contexts.empty()) return; context = contexts.front(); } } } _camera->setGraphicsContext(context); _camera->setRenderOrder(osg::Camera::POST_RENDER, 10); _camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); _camera->setViewMatrix(osg::Matrix::identity()); setWindowSize(context->getTraits()->width, context->getTraits()->height); // only clear the depth buffer _camera->setClearMask(0); _camera->setAllowEventFocus(false); _camera->setRenderer(new Renderer(_camera.get())); _initialized = true; } void StatsHandler::setWindowSize(int width, int height) { if (width <= 0 || height <= 0) return; _camera->setViewport(0, 0, width, height); if (fabs(height*_statsWidth) <= fabs(width*_statsHeight)) { _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,width*_statsHeight/height,0.0,_statsHeight)); } else { _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,_statsHeight-height*_statsWidth/width,_statsHeight)); } } // Drawcallback to draw averaged attribute struct AveragedValueTextDrawCallback : public virtual osg::Drawable::DrawCallback { AveragedValueTextDrawCallback(osg::Stats* stats, const std::string& name, int frameDelta, bool averageInInverseSpace, double multiplier): _stats(stats), _attributeName(name), _frameDelta(frameDelta), _averageInInverseSpace(averageInInverseSpace), _multiplier(multiplier), _tickLastUpdated(0) { } /** do customized draw code.*/ virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { osgText::Text* text = (osgText::Text*)drawable; osg::Timer_t tick = osg::Timer::instance()->tick(); double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick); if (delta>50) // update every 50ms { _tickLastUpdated = tick; double value; if (_stats->getAveragedAttribute( _attributeName, value, _averageInInverseSpace)) { char tmpText[128]; sprintf(tmpText,"%4.2f",value * _multiplier); text->setText(tmpText); } else { text->setText(""); } } text->drawImplementation(renderInfo); } osg::ref_ptr _stats; std::string _attributeName; int _frameDelta; bool _averageInInverseSpace; double _multiplier; mutable osg::Timer_t _tickLastUpdated; }; // Drawcallback to draw raw attribute struct RawValueTextDrawCallback : public virtual osg::Drawable::DrawCallback { RawValueTextDrawCallback(osg::Stats* stats, const std::string& name, int frameDelta, double multiplier): _stats(stats), _attributeName(name), _frameDelta(frameDelta), _multiplier(multiplier), _tickLastUpdated(0) { } /** do customized draw code.*/ virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { osgText::Text* text = (osgText::Text*)drawable; osg::Timer_t tick = osg::Timer::instance()->tick(); double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick); if (delta>50) // update every 50ms { _tickLastUpdated = tick; unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); double value; if (_stats->getAttribute(frameNumber, _attributeName, value)) { char tmpText[128]; sprintf(tmpText,"%4.2f",value * _multiplier); text->setText(tmpText); } else { text->setText(""); } } text->drawImplementation(renderInfo); } osg::ref_ptr _stats; std::string _attributeName; int _frameDelta; double _multiplier; mutable osg::Timer_t _tickLastUpdated; }; struct CameraSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback { CameraSceneStatsTextDrawCallback(osg::Camera* camera, int cameraNumber): _camera(camera), _tickLastUpdated(0), _cameraNumber(cameraNumber) { } /** do customized draw code.*/ virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { if (!_camera) return; osgText::Text* text = (osgText::Text*)drawable; osg::Timer_t tick = osg::Timer::instance()->tick(); double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick); if (delta > 100) // update every 100ms { _tickLastUpdated = tick; std::ostringstream viewStr; viewStr.clear(); osg::Stats* stats = _camera->getStats(); osgViewer::Renderer* renderer = dynamic_cast(_camera->getRenderer()); if (stats && renderer) { viewStr.setf(std::ios::left, std::ios::adjustfield); viewStr.width(14); // Used fixed formatting, as scientific will switch to "...e+.." notation for // large numbers of vertices/drawables/etc. viewStr.setf(std::ios::fixed); viewStr.precision(0); viewStr << std::setw(1) << "#" << _cameraNumber << std::endl; // Camera name if (!_camera->getName().empty()) viewStr << _camera->getName(); viewStr << std::endl; unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); if (!(renderer->getGraphicsThreadDoesCull())) { --frameNumber; } #define STATS_ATTRIBUTE(str) \ if (stats->getAttribute(frameNumber, str, value)) \ viewStr << std::setw(8) << value << std::endl; \ else \ viewStr << std::setw(8) << "." << std::endl; \ double value = 0.0; STATS_ATTRIBUTE("Visible number of lights") STATS_ATTRIBUTE("Visible number of render bins") STATS_ATTRIBUTE("Visible depth") STATS_ATTRIBUTE("Number of StateGraphs") STATS_ATTRIBUTE("Visible number of impostors") STATS_ATTRIBUTE("Visible number of drawables") STATS_ATTRIBUTE("Number of ordered leaves") STATS_ATTRIBUTE("Visible number of fast drawables") STATS_ATTRIBUTE("Visible vertex count") STATS_ATTRIBUTE("Visible number of PrimitiveSets") STATS_ATTRIBUTE("Visible number of GL_POINTS") STATS_ATTRIBUTE("Visible number of GL_LINES") STATS_ATTRIBUTE("Visible number of GL_LINE_STRIP") STATS_ATTRIBUTE("Visible number of GL_LINE_LOOP") STATS_ATTRIBUTE("Visible number of GL_TRIANGLES") STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_STRIP") STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_FAN") STATS_ATTRIBUTE("Visible number of GL_QUADS") STATS_ATTRIBUTE("Visible number of GL_QUAD_STRIP") STATS_ATTRIBUTE("Visible number of GL_POLYGON") text->setText(viewStr.str()); } } text->drawImplementation(renderInfo); } osg::observer_ptr _camera; mutable osg::Timer_t _tickLastUpdated; int _cameraNumber; }; struct ViewSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback { ViewSceneStatsTextDrawCallback(osgViewer::View* view, int viewNumber): _view(view), _tickLastUpdated(0), _viewNumber(viewNumber) { } /** do customized draw code.*/ virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { if (!_view) return; osgText::Text* text = (osgText::Text*)drawable; osg::Timer_t tick = osg::Timer::instance()->tick(); double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick); if (delta > 200) // update every 100ms { _tickLastUpdated = tick; osg::Stats* stats = _view->getStats(); if (stats) { std::ostringstream viewStr; viewStr.clear(); viewStr.setf(std::ios::left, std::ios::adjustfield); viewStr.width(20); viewStr.setf(std::ios::fixed); viewStr.precision(0); viewStr << std::setw(1) << "#" << _viewNumber; // View name if (!_view->getName().empty()) viewStr << ": " << _view->getName(); viewStr << std::endl; unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); // if (!(renderer->getGraphicsThreadDoesCull())) { --frameNumber; } #define STATS_ATTRIBUTE_PAIR(str1, str2) \ if (stats->getAttribute(frameNumber, str1, value)) \ viewStr << std::setw(9) << value; \ else \ viewStr << std::setw(9) << "."; \ if (stats->getAttribute(frameNumber, str2, value)) \ viewStr << std::setw(9) << value << std::endl; \ else \ viewStr << std::setw(9) << "." << std::endl; \ double value = 0.0; // header viewStr << std::setw(9) << "Unique" << std::setw(9) << "Instance" << std::endl; STATS_ATTRIBUTE_PAIR("Number of unique StateSet","Number of instanced Stateset") STATS_ATTRIBUTE_PAIR("Number of unique Group","Number of instanced Group") STATS_ATTRIBUTE_PAIR("Number of unique Transform","Number of instanced Transform") STATS_ATTRIBUTE_PAIR("Number of unique LOD","Number of instanced LOD") STATS_ATTRIBUTE_PAIR("Number of unique Switch","Number of instanced Switch") STATS_ATTRIBUTE_PAIR("Number of unique Geode","Number of instanced Geode") STATS_ATTRIBUTE_PAIR("Number of unique Drawable","Number of instanced Drawable") STATS_ATTRIBUTE_PAIR("Number of unique Geometry","Number of instanced Geometry") STATS_ATTRIBUTE_PAIR("Number of unique Vertices","Number of instanced Vertices") STATS_ATTRIBUTE_PAIR("Number of unique Primitives","Number of instanced Primitives") text->setText(viewStr.str()); } else { OSG_WARN<setText(""); } } text->drawImplementation(renderInfo); } osg::observer_ptr _view; mutable osg::Timer_t _tickLastUpdated; int _viewNumber; }; struct BlockDrawCallback : public virtual osg::Drawable::DrawCallback { BlockDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, osg::Stats* stats, const std::string& beginName, const std::string& endName, int frameDelta, int numFrames): _statsHandler(statsHandler), _xPos(xPos), _viewerStats(viewerStats), _stats(stats), _beginName(beginName), _endName(endName), _frameDelta(frameDelta), _numFrames(numFrames) {} /** do customized draw code.*/ virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { osg::Geometry* geom = (osg::Geometry*)drawable; osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray(); int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); int startFrame = frameNumber + _frameDelta - _numFrames + 1; int endFrame = frameNumber + _frameDelta; double referenceTime; if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime)) { return; } unsigned int vi = 0; double beginValue, endValue; double minWidth = .0002; for(int i = startFrame; i <= endFrame; ++i) { if (_stats->getAttribute( i, _beginName, beginValue) && _stats->getAttribute( i, _endName, endValue) ) { (*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier(); (*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier(); (*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier(); if (endValue - beginValue < minWidth) endValue = beginValue + minWidth; (*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier(); } } vertices->dirty(); drawable->drawImplementation(renderInfo); } StatsHandler* _statsHandler; float _xPos; osg::ref_ptr _viewerStats; osg::ref_ptr _stats; std::string _beginName; std::string _endName; int _frameDelta; int _numFrames; }; osg::Geometry* StatsHandler::createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color) { osg::StateSet *ss = new osg::StateSet; osg::Geometry* geometry = new osg::Geometry; geometry->setUseDisplayList(false); geometry->setStateSet(ss); osg::Vec3Array* vertices = new osg::Vec3Array; geometry->setVertexArray(vertices); vertices->push_back(osg::Vec3(pos.x(), pos.y(), 0)); vertices->push_back(osg::Vec3(pos.x(), pos.y()-height,0)); vertices->push_back(osg::Vec3(pos.x()+width, pos.y()-height,0)); vertices->push_back(osg::Vec3(pos.x()+width, pos.y(),0)); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(color); geometry->setColorArray(colors, osg::Array::BIND_OVERALL); osg::DrawElementsUShort *base = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_FAN,0); base->push_back(0); base->push_back(1); base->push_back(2); base->push_back(3); geometry->addPrimitiveSet(base); return geometry; } struct StatsGraph : public osg::MatrixTransform { StatsGraph(osg::Vec3 pos, float width, float height) : _pos(pos), _width(width), _height(height), _statsGraphGeode(new osg::Geode) { _pos -= osg::Vec3(0, height, 0.1); setMatrix(osg::Matrix::translate(_pos)); addChild(_statsGraphGeode.get()); } void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "") { _statsGraphGeode->addDrawable(new Graph(_pos, _width, _height, viewerStats, stats, color, max, nameBegin, nameEnd)); } osg::Vec3 _pos; float _width; float _height; osg::ref_ptr _statsGraphGeode; protected: struct Graph : public osg::Geometry { Graph(const osg::Vec3& pos, float width, float height, osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "") { setUseDisplayList(false); setDataVariance(osg::Object::DYNAMIC); osg::ref_ptr vbo = new osg::VertexBufferObject; vbo->setUsage(GL_DYNAMIC_DRAW); vbo->getProfile()._size = (width)*12; osg::ref_ptr vertices = new osg::Vec3Array; vertices->setBufferObject(vbo.get()); vertices->reserve(width); setVertexArray(vertices.get()); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(color); setColorArray(colors, osg::Array::BIND_OVERALL); addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0)); setDrawCallback(new GraphUpdateCallback(this, pos, width, height, viewerStats, stats, max, nameBegin, nameEnd)); } }; struct GraphUpdateCallback : public osg::Drawable::DrawCallback { GraphUpdateCallback(osg::Geometry* geometry, const osg::Vec3& pos, float width, float height, osg::Stats* viewerStats, osg::Stats* stats, float max, const std::string& nameBegin, const std::string& nameEnd = "") : _pos(pos), _width((unsigned int)width), _height((unsigned int)height), _curX(0), _viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd) { _vertices = dynamic_cast(geometry->getVertexArray()); _drawArrays = dynamic_cast(geometry->getPrimitiveSet(0)); } virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); // Get stats double value; if (_nameEnd.empty()) { if (!_stats->getAveragedAttribute( _nameBegin, value, true )) { value = 0.0; } } else { double beginValue, endValue; if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) && _stats->getAttribute( frameNumber, _nameEnd, endValue) ) { value = endValue - beginValue; } else { value = 0.0; } } // Add new vertex for this frame. value = osg::clampTo(value, 0.0, double(_max)); _vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0)); // One vertex per pixel in X. int excedent = _vertices->size() - _width; if (excedent > 0) { _vertices->erase(_vertices->begin(), _vertices->begin() + excedent); } // Update primitive set. _drawArrays->setFirst(0); _drawArrays->setCount(_vertices->size()); // Make the graph scroll when there is enough data. // Note: We check the frame number so that even if we have // many graphs, the transform is translated only once per // frame. //static const float increment = -1.0; if (GraphUpdateCallback::_frameNumber != frameNumber) { // We know the exact layout of this part of the scene // graph, so this is OK... osg::MatrixTransform* transform = const_cast(drawable->getParent(0)->getParent(0)->asTransform()->asMatrixTransform()); if (transform) { //osg::Matrix matrix = transform->getMatrix(); //matrix.setTrans(-(*vertices)[0].x(), matrix.getTrans().y(), matrix.getTrans().z()); transform->setMatrix(osg::Matrix::translate(_pos + osg::Vec3(-(*_vertices)[0].x(), 0, 0))); } } _vertices->dirty(); _curX++; GraphUpdateCallback::_frameNumber = frameNumber; drawable->drawImplementation(renderInfo); } osg::ref_ptr _vertices; osg::ref_ptr _drawArrays; const osg::Vec3 _pos; const unsigned int _width; const unsigned int _height; mutable unsigned int _curX; osg::Stats* _viewerStats; osg::Stats* _stats; const float _max; const std::string _nameBegin; const std::string _nameEnd; static unsigned int _frameNumber; }; }; unsigned int StatsGraph::GraphUpdateCallback::_frameNumber = 0; osg::Geometry* StatsHandler::createGeometry(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks) { osg::Geometry* geometry = new osg::Geometry; geometry->setUseDisplayList(false); geometry->setDataVariance(osg::Object::DYNAMIC); osg::Vec3Array* vertices = new osg::Vec3Array; geometry->setVertexArray(vertices); vertices->reserve(numBlocks*4); osg::DrawElementsUShort* primitives = new osg::DrawElementsUShort(GL_TRIANGLES); for(unsigned int i=0; isize(); vertices->push_back(pos+osg::Vec3(i*20, height, 0.0)); vertices->push_back(pos+osg::Vec3(i*20, 0.0, 0.0)); vertices->push_back(pos+osg::Vec3(i*20+10.0, 0.0, 0.0)); vertices->push_back(pos+osg::Vec3(i*20+10.0, height, 0.0)); primitives->push_back(vi); primitives->push_back(vi+1); primitives->push_back(vi+2); primitives->push_back(vi); primitives->push_back(vi+2); primitives->push_back(vi+3); } osg::Vec4Array* colours = new osg::Vec4Array; colours->push_back(colour); geometry->setColorArray(colours, osg::Array::BIND_OVERALL); geometry->addPrimitiveSet(primitives); return geometry; } struct FrameMarkerDrawCallback : public virtual osg::Drawable::DrawCallback { FrameMarkerDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, int frameDelta, int numFrames): _statsHandler(statsHandler), _xPos(xPos), _viewerStats(viewerStats), _frameDelta(frameDelta), _numFrames(numFrames) {} /** do customized draw code.*/ virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { osg::Geometry* geom = (osg::Geometry*)drawable; osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray(); int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); int startFrame = frameNumber + _frameDelta - _numFrames + 1; int endFrame = frameNumber + _frameDelta; double referenceTime; if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime)) { return; } unsigned int vi = 0; double currentReferenceTime; for(int i = startFrame; i <= endFrame; ++i) { if (_viewerStats->getAttribute( i, "Reference time", currentReferenceTime)) { (*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier(); (*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier(); } } vertices->dirty(); drawable->drawImplementation(renderInfo); } StatsHandler* _statsHandler; float _xPos; osg::ref_ptr _viewerStats; std::string _endName; int _frameDelta; int _numFrames; }; struct PagerCallback : public virtual osg::NodeCallback { PagerCallback( osgDB::DatabasePager* dp, osgText::Text* minValue, osgText::Text* maxValue, osgText::Text* averageValue, osgText::Text* filerequestlist, osgText::Text* compilelist, double multiplier): _dp(dp), _minValue(minValue), _maxValue(maxValue), _averageValue(averageValue), _filerequestlist(filerequestlist), _compilelist(compilelist), _multiplier(multiplier) { } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (_dp.valid()) { char tmpText[128]; double value = _dp->getAverageTimeToMergeTiles(); if (value>= 0.0 && value <= 1000) { sprintf(tmpText,"%4.0f",value * _multiplier); _averageValue->setText(tmpText); } else { _averageValue->setText(""); } value = _dp->getMinimumTimeToMergeTile(); if (value>= 0.0 && value <= 1000) { sprintf(tmpText,"%4.0f",value * _multiplier); _minValue->setText(tmpText); } else { _minValue->setText(""); } value = _dp->getMaximumTimeToMergeTile(); if (value>= 0.0 && value <= 1000) { sprintf(tmpText,"%4.0f",value * _multiplier); _maxValue->setText(tmpText); } else { _maxValue->setText(""); } sprintf(tmpText,"%4d", _dp->getFileRequestListSize()); _filerequestlist->setText(tmpText); sprintf(tmpText,"%4d", _dp->getDataToCompileListSize()); _compilelist->setText(tmpText); } traverse(node,nv); } osg::observer_ptr _dp; osg::ref_ptr _minValue; osg::ref_ptr _maxValue; osg::ref_ptr _averageValue; osg::ref_ptr _filerequestlist; osg::ref_ptr _compilelist; double _multiplier; }; osg::Geometry* StatsHandler::createFrameMarkers(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks) { osg::Geometry* geometry = new osg::Geometry; geometry->setUseDisplayList(false); geometry->setDataVariance(osg::Object::DYNAMIC); osg::Vec3Array* vertices = new osg::Vec3Array; geometry->setVertexArray(vertices); vertices->reserve(numBlocks*2); for(unsigned int i=0; ipush_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, height, 0.0)); vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, 0.0, 0.0)); } osg::Vec4Array* colours = new osg::Vec4Array; colours->push_back(colour); geometry->setColorArray(colours, osg::Array::BIND_OVERALL); geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numBlocks*2)); return geometry; } osg::Geometry* StatsHandler::createTick(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numTicks) { osg::Geometry* geometry = new osg::Geometry; geometry->setUseDisplayList(false); geometry->setDataVariance(osg::Object::DYNAMIC); osg::Vec3Array* vertices = new osg::Vec3Array; geometry->setVertexArray(vertices); vertices->reserve(numTicks*2); for(unsigned int i=0; ipush_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, tickHeight , 0.0)); vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, 0.0, 0.0)); } osg::Vec4Array* colours = new osg::Vec4Array; colours->push_back(colour); geometry->setColorArray(colours, osg::Array::BIND_OVERALL); geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numTicks*2)); return geometry; } void StatsHandler::setUpScene(osgViewer::ViewerBase* viewer) { _switch = new osg::Switch; _camera->addChild(_switch.get()); osg::StateSet* stateset = _switch->getOrCreateStateSet(); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); stateset->setMode(GL_BLEND,osg::StateAttribute::ON); stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF); #ifdef OSG_GL1_AVAILABLE stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED); #endif // collect all the relevant cameras ViewerBase::Cameras validCameras; collectWhichCamerasToRenderStatsFor(viewer, validCameras); ViewerBase::Cameras cameras; for(ViewerBase::Cameras::iterator itr = validCameras.begin(); itr != validCameras.end(); ++itr) { if ((*itr)->getStats()) { cameras.push_back(*itr); } } // check for query time support unsigned int numCamrasWithTimerQuerySupport = 0; for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { if ((*citr)->getGraphicsContext()) { const osg::State* state = (*citr)->getGraphicsContext()->getState(); const osg::GLExtensions* extensions = state->get(); if (extensions && (((extensions->isARBTimerQuerySupported && state->getTimestampBits() > 0)) || extensions->isTimerQuerySupported)) { ++numCamrasWithTimerQuerySupport; } } } bool acquireGPUStats = numCamrasWithTimerQuerySupport==cameras.size(); osg::Vec3 pos(_leftPos, _statsHeight-24.0f,0.0f); osg::Vec4 colorFR(1.0f,1.0f,1.0f,1.0f); osg::Vec4 colorFRAlpha(1.0f,1.0f,1.0f,0.5f); osg::Vec4 colorUpdate( 0.0f,1.0f,0.0f,1.0f); osg::Vec4 colorUpdateAlpha( 0.0f,1.0f,0.0f,0.5f); osg::Vec4 colorEvent(0.0f, 1.0f, 0.5f, 1.0f); osg::Vec4 colorEventAlpha(0.0f, 1.0f, 0.5f, 0.5f); osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f); osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f); osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f); osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f); osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f); osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f); osg::Vec4 colorDP( 1.0f,1.0f,0.5f,1.0f); // frame rate stats { osg::Geode* geode = new osg::Geode(); _frameRateChildNum = _switch->getNumChildren(); _switch->addChild(geode, false); osg::ref_ptr frameRateLabel = new osgText::Text; geode->addDrawable( frameRateLabel.get() ); frameRateLabel->setColor(colorFR); frameRateLabel->setFont(_font); frameRateLabel->setCharacterSize(_characterSize); frameRateLabel->setPosition(pos); #ifdef _DEBUG osg::Vec4 colorDFR(1.0f, 0.0f, 0.0f, 1.0f); frameRateLabel->setColor(colorDFR); frameRateLabel->setText("DEBUG Frame Rate: "); #else frameRateLabel->setColor(colorFR); frameRateLabel->setText("Frame Rate: "); #endif pos.x() = frameRateLabel->getBoundingBox().xMax(); osg::ref_ptr frameRateValue = new osgText::Text; geode->addDrawable( frameRateValue.get() ); frameRateValue->setColor(colorFR); frameRateValue->setFont(_font); frameRateValue->setCharacterSize(_characterSize); frameRateValue->setPosition(pos); frameRateValue->setText("0.0"); frameRateValue->setDataVariance(osg::Object::DYNAMIC); frameRateValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Frame rate",-1, true, 1.0)); pos.y() -= _characterSize*_lineHeight; } osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3); osg::Vec4 staticTextColor(1.0, 1.0, 0.0f, 1.0); osg::Vec4 dynamicTextColor(1.0, 1.0, 1.0f, 1.0); float backgroundMargin = 5; float backgroundSpacing = 3; // viewer stats { osg::Group* group = new osg::Group; _viewerChildNum = _switch->getNumChildren(); _switch->addChild(group, false); _statsGeode = new osg::Geode(); group->addChild(_statsGeode.get()); { pos.x() = _leftPos; _threadingModelText = new osgText::Text; _statsGeode->addDrawable( _threadingModelText.get() ); _threadingModelText->setColor(colorFR); _threadingModelText->setFont(_font); _threadingModelText->setCharacterSize(_characterSize); _threadingModelText->setPosition(pos); updateThreadingModelText(); pos.y() -= _characterSize*_lineHeight; } float topOfViewerStats = pos.y() + _characterSize; double cameraSize = _lineHeight * 3.0 * cameras.size(); if(!acquireGPUStats) //reduce size if GPU stats not needed { cameraSize -= _lineHeight * cameras.size(); } double userStatsLinesSize = _lineHeight * _userStatsLines.size(); _statsGeode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), _statsWidth - 2 * backgroundMargin, (3 + cameraSize + userStatsLinesSize) * _characterSize + 2 * backgroundMargin, backgroundColor) ); // Add user stats lines before the normal viewer and per-camera stats. for (unsigned int i = 0; i < _userStatsLines.size(); ++i) { pos.x() = _leftPos; UserStatsLine& line = _userStatsLines[i]; createTimeStatsLine(line.label, pos, line.textColor, line.barColor, viewer->getViewerStats(), viewer->getViewerStats(), line.timeTakenName, line.multiplier, line.average, line.averageInInverseSpace, line.beginTimeName, line.endTimeName); pos.y() -= _characterSize*_lineHeight; } { pos.x() = _leftPos; createTimeStatsLine("Event", pos, colorUpdate, colorUpdateAlpha, viewer->getViewerStats(), viewer->getViewerStats(), "Event traversal time taken", 1000.0, true, false, "Event traversal begin time", "Event traversal end time"); pos.y() -= _characterSize*_lineHeight; } { pos.x() = _leftPos; createTimeStatsLine("Update", pos, colorUpdate, colorUpdateAlpha, viewer->getViewerStats(), viewer->getViewerStats(), "Update traversal time taken", 1000.0, true, false, "Update traversal begin time", "Update traversal end time"); pos.y() -= _characterSize*_lineHeight; } pos.x() = _leftPos; // add camera stats for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { createCameraTimeStats(pos, acquireGPUStats, viewer->getViewerStats(), *citr); } // add frame ticks { osg::Geode* geode = new osg::Geode; group->addChild(geode); osg::Vec4 colourTicks(1.0f,1.0f,1.0f, 0.5f); pos.x() = _startBlocks; pos.y() += _characterSize; float height = topOfViewerStats - pos.y(); osg::Geometry* ticks = createTick(pos, 5.0f, colourTicks, 100); geode->addDrawable(ticks); osg::Geometry* frameMarkers = createFrameMarkers(pos, height, colourTicks, _numBlocks + 1); frameMarkers->setDrawCallback(new FrameMarkerDrawCallback(this, _startBlocks, viewer->getViewerStats(), 0, _numBlocks + 1)); geode->addDrawable(frameMarkers); pos.x() = _leftPos; } // Stats line graph { pos.y() -= (backgroundSpacing + 2 * backgroundMargin); float width = _statsWidth - 4 * backgroundMargin; float height = 5 * _characterSize; // Create a stats graph and add any stats we want to track with it. StatsGraph* statsGraph = new StatsGraph(pos, width, height); group->addChild(statsGraph); statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorFR, 100, "Frame rate"); statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorEvent, 0.016, "Event traversal time taken"); statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorUpdate, 0.016, "Update traversal time taken"); for (unsigned int i = 0; i < _userStatsLines.size(); ++i) { UserStatsLine& line = _userStatsLines[i]; if (!line.timeTakenName.empty() && line.average) { statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), line.textColor, line.maxValue, line.timeTakenName); } } for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorCull, 0.016, "Cull traversal time taken"); statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorDraw, 0.016, "Draw traversal time taken"); if(acquireGPUStats) { statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorGPU, 0.016, "GPU draw time taken"); } } _statsGeode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0), width + 2 * backgroundMargin, height + 2 * backgroundMargin, backgroundColor) ); pos.x() = _leftPos; pos.y() -= height + 2 * backgroundMargin; } // Databasepager stats ViewerBase::Scenes scenes; viewer->getScenes(scenes); for(ViewerBase::Scenes::iterator itr = scenes.begin(); itr != scenes.end(); ++itr) { Scene* scene = *itr; osgDB::DatabasePager* dp = scene->getDatabasePager(); if (dp && dp->isRunning()) { pos.y() -= (_characterSize + backgroundSpacing); _statsGeode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), _statsWidth - 2 * backgroundMargin, _characterSize + 2 * backgroundMargin, backgroundColor)); osg::ref_ptr averageLabel = new osgText::Text; _statsGeode->addDrawable( averageLabel.get() ); averageLabel->setColor(colorDP); averageLabel->setFont(_font); averageLabel->setCharacterSize(_characterSize); averageLabel->setPosition(pos); averageLabel->setText("DatabasePager time to merge new tiles - average: "); pos.x() = averageLabel->getBoundingBox().xMax(); osg::ref_ptr averageValue = new osgText::Text; _statsGeode->addDrawable( averageValue.get() ); averageValue->setColor(colorDP); averageValue->setFont(_font); averageValue->setCharacterSize(_characterSize); averageValue->setPosition(pos); averageValue->setText("1000"); averageValue->setDataVariance(osg::Object::DYNAMIC); pos.x() = averageValue->getBoundingBox().xMax() + 2.0f*_characterSize; osg::ref_ptr minLabel = new osgText::Text; _statsGeode->addDrawable( minLabel.get() ); minLabel->setColor(colorDP); minLabel->setFont(_font); minLabel->setCharacterSize(_characterSize); minLabel->setPosition(pos); minLabel->setText("min: "); pos.x() = minLabel->getBoundingBox().xMax(); osg::ref_ptr minValue = new osgText::Text; _statsGeode->addDrawable( minValue.get() ); minValue->setColor(colorDP); minValue->setFont(_font); minValue->setCharacterSize(_characterSize); minValue->setPosition(pos); minValue->setText("1000"); minValue->setDataVariance(osg::Object::DYNAMIC); pos.x() = minValue->getBoundingBox().xMax() + 2.0f*_characterSize; osg::ref_ptr maxLabel = new osgText::Text; _statsGeode->addDrawable( maxLabel.get() ); maxLabel->setColor(colorDP); maxLabel->setFont(_font); maxLabel->setCharacterSize(_characterSize); maxLabel->setPosition(pos); maxLabel->setText("max: "); pos.x() = maxLabel->getBoundingBox().xMax(); osg::ref_ptr maxValue = new osgText::Text; _statsGeode->addDrawable( maxValue.get() ); maxValue->setColor(colorDP); maxValue->setFont(_font); maxValue->setCharacterSize(_characterSize); maxValue->setPosition(pos); maxValue->setText("1000"); maxValue->setDataVariance(osg::Object::DYNAMIC); pos.x() = maxValue->getBoundingBox().xMax(); osg::ref_ptr requestsLabel = new osgText::Text; _statsGeode->addDrawable( requestsLabel.get() ); requestsLabel->setColor(colorDP); requestsLabel->setFont(_font); requestsLabel->setCharacterSize(_characterSize); requestsLabel->setPosition(pos); requestsLabel->setText("requests: "); pos.x() = requestsLabel->getBoundingBox().xMax(); osg::ref_ptr requestList = new osgText::Text; _statsGeode->addDrawable( requestList.get() ); requestList->setColor(colorDP); requestList->setFont(_font); requestList->setCharacterSize(_characterSize); requestList->setPosition(pos); requestList->setText("0"); requestList->setDataVariance(osg::Object::DYNAMIC); pos.x() = requestList->getBoundingBox().xMax() + 2.0f*_characterSize;; osg::ref_ptr compileLabel = new osgText::Text; _statsGeode->addDrawable( compileLabel.get() ); compileLabel->setColor(colorDP); compileLabel->setFont(_font); compileLabel->setCharacterSize(_characterSize); compileLabel->setPosition(pos); compileLabel->setText("tocompile: "); pos.x() = compileLabel->getBoundingBox().xMax(); osg::ref_ptr compileList = new osgText::Text; _statsGeode->addDrawable( compileList.get() ); compileList->setColor(colorDP); compileList->setFont(_font); compileList->setCharacterSize(_characterSize); compileList->setPosition(pos); compileList->setText("0"); compileList->setDataVariance(osg::Object::DYNAMIC); pos.x() = maxLabel->getBoundingBox().xMax(); _statsGeode->setCullCallback(new PagerCallback(dp, minValue.get(), maxValue.get(), averageValue.get(), requestList.get(), compileList.get(), 1000.0)); } pos.x() = _leftPos; } } // Camera scene stats { pos.y() -= (_characterSize + backgroundSpacing + 2 * backgroundMargin); osg::Group* group = new osg::Group; _cameraSceneChildNum = _switch->getNumChildren(); _switch->addChild(group, false); osg::Geode* geode = new osg::Geode(); geode->setCullingActive(false); group->addChild(geode); geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), 10 * _characterSize + 2 * backgroundMargin, 22 * _characterSize + 2 * backgroundMargin, backgroundColor)); // Camera scene & primitive stats static text osg::ref_ptr camStaticText = new osgText::Text; geode->addDrawable( camStaticText.get() ); camStaticText->setColor(staticTextColor); camStaticText->setFont(_font); camStaticText->setCharacterSize(_characterSize); camStaticText->setPosition(pos); std::ostringstream viewStr; viewStr.clear(); viewStr.setf(std::ios::left, std::ios::adjustfield); viewStr.width(14); viewStr << "Camera" << std::endl; viewStr << "" << std::endl; // placeholder for Camera name viewStr << "Lights" << std::endl; viewStr << "Bins" << std::endl; viewStr << "Depth" << std::endl; viewStr << "State graphs" << std::endl; viewStr << "Imposters" << std::endl; viewStr << "Drawables" << std::endl; viewStr << "Sorted Drawables" << std::endl; viewStr << "Fast Drawables" << std::endl; viewStr << "Vertices" << std::endl; viewStr << "PrimitiveSets" << std::endl; viewStr << "Points" << std::endl; viewStr << "Lines" << std::endl; viewStr << "Line strips" << std::endl; viewStr << "Line loops" << std::endl; viewStr << "Triangles" << std::endl; viewStr << "Tri. strips" << std::endl; viewStr << "Tri. fans" << std::endl; viewStr << "Quads" << std::endl; viewStr << "Quad strips" << std::endl; viewStr << "Polygons" << std::endl; viewStr.setf(std::ios::right,std::ios::adjustfield); camStaticText->setText(viewStr.str()); // Move camera block to the right pos.x() += 10 * _characterSize + 2 * backgroundMargin + backgroundSpacing; // Add camera scene stats, one block per camera int cameraCounter = 0; for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), 5 * _characterSize + 2 * backgroundMargin, 22 * _characterSize + 2 * backgroundMargin, backgroundColor)); // Camera scene stats osg::ref_ptr camStatsText = new osgText::Text; geode->addDrawable( camStatsText.get() ); camStatsText->setColor(dynamicTextColor); camStatsText->setFont(_font); camStatsText->setCharacterSize(_characterSize); camStatsText->setPosition(pos); camStatsText->setText(""); camStatsText->setDataVariance(osg::Object::DYNAMIC); camStatsText->setDrawCallback(new CameraSceneStatsTextDrawCallback(*citr, cameraCounter)); // Move camera block to the right pos.x() += 5 * _characterSize + 2 * backgroundMargin + backgroundSpacing; cameraCounter++; } } // Viewer scene stats { osg::Group* group = new osg::Group; _viewerSceneChildNum = _switch->getNumChildren(); _switch->addChild(group, false); osg::Geode* geode = new osg::Geode(); geode->setCullingActive(false); group->addChild(geode); geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), 6 * _characterSize + 2 * backgroundMargin, 12 * _characterSize + 2 * backgroundMargin, backgroundColor)); // View scene stats static text osg::ref_ptr camStaticText = new osgText::Text; geode->addDrawable( camStaticText.get() ); camStaticText->setColor(staticTextColor); camStaticText->setFont(_font); camStaticText->setCharacterSize(_characterSize); camStaticText->setPosition(pos); std::ostringstream viewStr; viewStr.clear(); viewStr.setf(std::ios::left, std::ios::adjustfield); viewStr.width(14); viewStr << "View" << std::endl; viewStr << " " << std::endl; viewStr << "Stateset" << std::endl; viewStr << "Group" << std::endl; viewStr << "Transform" << std::endl; viewStr << "LOD" << std::endl; viewStr << "Switch" << std::endl; viewStr << "Geode" << std::endl; viewStr << "Drawable" << std::endl; viewStr << "Geometry" << std::endl; viewStr << "Vertices" << std::endl; viewStr << "Primitives" << std::endl; viewStr.setf(std::ios::right, std::ios::adjustfield); camStaticText->setText(viewStr.str()); // Move viewer block to the right pos.x() += 6 * _characterSize + 2 * backgroundMargin + backgroundSpacing; std::vector views; viewer->getViews(views); std::vector::iterator it; int viewCounter = 0; for (it = views.begin(); it != views.end(); ++it) { geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), 10 * _characterSize + 2 * backgroundMargin, 12 * _characterSize + 2 * backgroundMargin, backgroundColor)); // Text for scene statistics osgText::Text* text = new osgText::Text; geode->addDrawable( text ); text->setColor(dynamicTextColor); text->setFont(_font); text->setCharacterSize(_characterSize); text->setPosition(pos); text->setDataVariance(osg::Object::DYNAMIC); text->setDrawCallback(new ViewSceneStatsTextDrawCallback(*it, viewCounter)); pos.x() += 10 * _characterSize + 2 * backgroundMargin + backgroundSpacing; viewCounter++; } } } void StatsHandler::createTimeStatsLine(const std::string& lineLabel, osg::Vec3 pos, const osg::Vec4& textColor, const osg::Vec4& barColor, osg::Stats* viewerStats, osg::Stats* stats, const std::string& timeTakenName, float multiplier, bool average, bool averageInInverseSpace, const std::string& beginTimeName, const std::string& endTimeName) { osg::ref_ptr label = new osgText::Text; _statsGeode->addDrawable( label.get() ); label->setColor(textColor); label->setFont(_font); label->setCharacterSize(_characterSize); label->setPosition(pos); label->setText(lineLabel + ": "); pos.x() = label->getBoundingBox().xMax(); osg::ref_ptr value = new osgText::Text; _statsGeode->addDrawable( value.get() ); value->setColor(textColor); value->setFont(_font); value->setCharacterSize(_characterSize); value->setPosition(pos); value->setText("0.0"); value->setDataVariance(osg::Object::DYNAMIC); if (!timeTakenName.empty()) { if (average) { value->setDrawCallback(new AveragedValueTextDrawCallback(stats, timeTakenName, -1, averageInInverseSpace, multiplier)); } else { value->setDrawCallback(new RawValueTextDrawCallback(stats, timeTakenName, -1, multiplier)); } } if (!beginTimeName.empty() && !endTimeName.empty()) { pos.x() = _startBlocks; osg::Geometry* geometry = createGeometry(pos, _characterSize *0.8, barColor, _numBlocks); geometry->setDrawCallback(new BlockDrawCallback(this, _startBlocks, viewerStats, stats, beginTimeName, endTimeName, -1, _numBlocks)); _statsGeode->addDrawable(geometry); } } void StatsHandler::createCameraTimeStats(osg::Vec3& pos, bool acquireGPUStats, osg::Stats* viewerStats, osg::Camera* camera) { osg::Stats* stats = camera->getStats(); if (!stats) return; osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f); osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f); osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f); osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f); osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f); osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f); { pos.x() = _leftPos; createTimeStatsLine("Cull", pos, colorCull, colorCullAlpha, viewerStats, stats, "Cull traversal time taken", 1000.0, true, false, "Cull traversal begin time", "Cull traversal end time"); pos.y() -= _characterSize*_lineHeight; } { pos.x() = _leftPos; createTimeStatsLine("Draw", pos, colorDraw, colorDrawAlpha, viewerStats, stats, "Draw traversal time taken", 1000.0, true, false, "Draw traversal begin time", "Draw traversal end time"); pos.y() -= _characterSize*_lineHeight; } if (acquireGPUStats) { pos.x() = _leftPos; createTimeStatsLine("GPU", pos, colorGPU, colorGPUAlpha, viewerStats, stats, "GPU draw time taken", 1000.0, true, false, "GPU draw begin time", "GPU draw end time"); pos.y() -= _characterSize*_lineHeight; } } void StatsHandler::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding(_keyEventTogglesOnScreenStats,"On screen stats."); usage.addKeyboardMouseBinding(_keyEventPrintsOutStats,"Output stats to console."); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/0000755000175000017500000000000013151044751020651 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/Version.cpp0000644000175000017500000000152413151044751023004 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include extern "C" { const char* osgGAGetVersion() { return osgGetVersion(); } const char* osgGAGetLibraryName() { return "OpenSceneGraph GA (Gui Adapter) Library"; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/EventHandler.cpp0000644000175000017500000000345713151044751023745 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgGA; void EventHandler::operator()(osg::Node* node, osg::NodeVisitor* nv) { osgGA::EventVisitor* ev = dynamic_cast(nv); if (ev && ev->getActionAdapter() && !ev->getEvents().empty()) { for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin(); itr != ev->getEvents().end(); ++itr) { handle(itr->get(), node, nv); } } if (node->getNumChildrenRequiringEventTraversal()>0 || _nestedCallback.valid()) traverse(node,nv); } void EventHandler::event(osg::NodeVisitor* nv, osg::Drawable* drawable) { osgGA::EventVisitor* ev = dynamic_cast(nv); if (ev && ev->getActionAdapter() && !ev->getEvents().empty()) { for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin(); itr != ev->getEvents().end(); ++itr) { handle(itr->get(), drawable, nv); } } } bool EventHandler::handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv) { OSG_NOTICE<<"Handle event "< using namespace osgGA; Event::Event(): _handled(false), _time(0.0) {} Event::Event(const Event& rhs, const osg::CopyOp& copyop): osg::Object(rhs, copyop), _handled(rhs._handled), _time(rhs._time) {} OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/UFOManipulator.cpp0000644000175000017500000004030213151044751024221 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ /* Written by Don Burns */ #include #include #include #ifndef M_PI # define M_PI 3.14159265358979323846 /* pi */ #endif using namespace osgGA; UFOManipulator::UFOManipulator(): _t0(0.0), _shift(false), _ctrl(false) { _minHeightAboveGround = 2.0; _minDistanceInFront = 5.0; _speedAccelerationFactor = 0.4; _speedDecelerationFactor = 0.90; _directionRotationRate = 0.0; _directionRotationAcceleration = M_PI*0.00005; _directionRotationDeceleration = 0.90; _speedEpsilon = 0.02; _directionRotationEpsilon = 0.0001; _viewOffsetDelta = M_PI * 0.0025; _pitchOffsetRate = 0.0; _pitchOffset = 0.0; _yawOffsetRate = 0.0; _yawOffset = 0.0; _offset.makeIdentity(); _decelerateOffsetRate = true; _straightenOffset = false; _direction.set( 0,1,0); _stop(); } UFOManipulator::~UFOManipulator() { } bool UFOManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const { osg::ref_ptr lsi = new osgUtil::LineSegmentIntersector(start,end); osgUtil::IntersectionVisitor iv(lsi.get()); iv.setTraversalMask(_intersectTraversalMask); _node->accept(iv); if (lsi->containsIntersections()) { intersection = lsi->getIntersections().begin()->getWorldIntersectPoint(); return true; } return false; } void UFOManipulator::setNode( osg::Node *node ) { _node = node; if (getAutoComputeHomePosition()) computeHomePosition(); home(0.0); } const osg::Node* UFOManipulator::getNode() const { return _node.get(); } osg::Node* UFOManipulator::getNode() { return _node.get(); } const char* UFOManipulator::className() const { return "UFO"; } void UFOManipulator::setByMatrix( const osg::Matrixd &mat ) { _inverseMatrix = mat; _matrix.invert( _inverseMatrix ); _position.set( _inverseMatrix(3,0), _inverseMatrix(3,1), _inverseMatrix(3,2 )); osg::Matrix R(_inverseMatrix); R(3,0) = R(3,1) = R(3,2) = 0.0; _direction = osg::Vec3d(0,0,-1) * R; // camera up is +Z, regardless of CoordinateFrame _stop(); } void UFOManipulator::setByInverseMatrix( const osg::Matrixd &invmat) { _matrix = invmat; _inverseMatrix.invert( _matrix ); _position.set( _inverseMatrix(3,0), _inverseMatrix(3,1), _inverseMatrix(3,2 )); osg::Matrix R(_inverseMatrix); R(3,0) = R(3,1) = R(3,2) = 0.0; _direction = osg::Vec3d(0,0,-1) * R; // camera up is +Z, regardless of CoordinateFrame _stop(); } osg::Matrixd UFOManipulator::getMatrix() const { return (osg::Matrix::inverse(_offset) * _matrix); } osg::Matrixd UFOManipulator::getInverseMatrix() const { return (_inverseMatrix * _offset); } void UFOManipulator::computeHomePosition() { if( !_node.valid() ) return; osg::BoundingSphere bs = _node->getBound(); /* * Find the ground - Assumption: The ground is the hit of an intersection * from a line segment extending from above to below the database at its * horizontal center, that intersects the database closest to zero. */ osg::CoordinateFrame cf( getCoordinateFrame(bs.center()) ); // not sure what position to use here osg::Vec3d upVec( getUpVector(cf) ); osg::Vec3d A = bs.center() + (upVec*(bs.radius()*2)); osg::Vec3d B = bs.center() + (-upVec*(bs.radius()*2)); if( (B-A).length() == 0.0) { return; } // start with it high double ground = bs.radius() * 3; osg::Vec3d ip; if (intersect(A, B, ip)) { double d = ip.length(); if( d < ground ) ground = d; } else { //OSG_WARN<<"UFOManipulator : I can't find the ground!"<", "Reset the viewing angle to 0.0"); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Acceleration forward."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Acceleration backward (or deceleration forward"); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Rotate view and direction of travel to the left."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Rotate view and direction of travel to the right."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Brake. Gradually decelerates linear and rotational movement."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Accelerate up."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Accelerate down."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Accelerate (linearly) left."); usage.addKeyboardMouseBinding("UFO Manipulator: ","Accelerate (linearly) right."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Instant brake. Immediately stop all linear and rotational movement."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Rotate view (but not direction of travel) up."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Rotate view (but not direction of travel) down."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Rotate view (but not direction of travel) left."); usage.addKeyboardMouseBinding("UFO Manipulator: ", "Rotate view (but not direction of travel) right."); */ usage.addKeyboardMouseBinding("UFO: ", "Please see http://www.openscenegraph.org/html/UFOCameraManipulator.html"); // Keep this one as it might be confusing usage.addKeyboardMouseBinding("UFO: H", "Reset the viewing position to home"); } void UFOManipulator::_keyUp( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter & ) { switch( ea.getKey() ) { case osgGA::GUIEventAdapter::KEY_Control_L: case osgGA::GUIEventAdapter::KEY_Control_R: _ctrl = false; _decelerateOffsetRate = true; _straightenOffset = false; break; case osgGA::GUIEventAdapter::KEY_Shift_L: case osgGA::GUIEventAdapter::KEY_Shift_R: _shift = false; _decelerateUpSideRate = true; break; } } void UFOManipulator::_keyDown( const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter & ) { switch( ea.getKey() ) { case osgGA::GUIEventAdapter::KEY_Control_L: case osgGA::GUIEventAdapter::KEY_Control_R: _ctrl = true; break; case osgGA::GUIEventAdapter::KEY_Shift_L : case osgGA::GUIEventAdapter::KEY_Shift_R : _shift = true; break; case osgGA::GUIEventAdapter::KEY_Up: if( _ctrl ) { _pitchOffsetRate -= _viewOffsetDelta; _decelerateOffsetRate = false; } else { if( _shift ) { _upSpeed += _speedAccelerationFactor; _decelerateUpSideRate = false; } else _forwardSpeed += _speedAccelerationFactor; } break; case osgGA::GUIEventAdapter::KEY_Down: if( _ctrl ) { _pitchOffsetRate += _viewOffsetDelta; _decelerateOffsetRate = false; } else { if( _shift ) { _upSpeed -= _speedAccelerationFactor; _decelerateUpSideRate = false; } else _forwardSpeed -= _speedAccelerationFactor; } break; case osgGA::GUIEventAdapter::KEY_Right: if( _ctrl ) { _yawOffsetRate += _viewOffsetDelta; _decelerateOffsetRate = false; } else { if(_shift) { _sideSpeed += _speedAccelerationFactor; _decelerateUpSideRate = false; } else _directionRotationRate -= _directionRotationAcceleration; } break; case osgGA::GUIEventAdapter::KEY_Left: if( _ctrl ) { _yawOffsetRate -= _viewOffsetDelta; _decelerateOffsetRate = false; } else { if(_shift) { _sideSpeed -= _speedAccelerationFactor; _decelerateUpSideRate = false; } else _directionRotationRate += _directionRotationAcceleration; } break; case osgGA::GUIEventAdapter::KEY_Return: if( _ctrl ) { _straightenOffset = true; } break; case ' ': if( _shift ) { _stop(); } else { if( fabs(_forwardSpeed) > 0.0 ) { _forwardSpeed *= _speedDecelerationFactor; if( fabs(_forwardSpeed ) < _speedEpsilon ) _forwardSpeed = 0.0; } if( fabs(_sideSpeed) > 0.0 ) { _sideSpeed *= _speedDecelerationFactor; if( fabs( _sideSpeed ) < _speedEpsilon ) _sideSpeed = 0.0; } if( fabs(_upSpeed) > 0.0 ) { _upSpeed *= _speedDecelerationFactor; if( fabs( _upSpeed ) < _speedEpsilon ) _sideSpeed = 0.0; } if( fabs(_directionRotationRate ) > 0.0 ) { _directionRotationRate *= _directionRotationDeceleration; if( fabs( _directionRotationRate ) < _directionRotationEpsilon ) _directionRotationRate = 0.0; } } break; case 'H': home(ea.getTime()); break; } } void UFOManipulator::_frame( const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter & ) { double t1 = ea.getTime(); if( _t0 == 0.0 ) { _t0 = ea.getTime(); _dt = 0.0; } else { _dt = t1 - _t0; _t0 = t1; } osg::CoordinateFrame cf( getCoordinateFrame(_position) ); osg::Vec3d upVec( getUpVector(cf) ); if( fabs( _directionRotationRate ) > _directionRotationEpsilon ) { _direction = _direction * osg::Matrix::rotate( _directionRotationRate, upVec); } { osg::Vec3d _sideVec = _direction * osg::Matrix::rotate( -M_PI*0.5, upVec); _position += ((_direction * _forwardSpeed) + (_sideVec * _sideSpeed) + (upVec * _upSpeed)) * _dt; } _pitchOffset += _pitchOffsetRate * _dt; if( _pitchOffset >= M_PI || _pitchOffset < -M_PI ) _pitchOffset *= -1; _yawOffset += _yawOffsetRate * _dt; if( _yawOffset >= M_PI || _yawOffset < -M_PI ) _yawOffset *= -1; _offset = osg::Matrix::rotate( _yawOffset, getSideVector(cf), _pitchOffset, getFrontVector(cf), 0.0, upVec); _adjustPosition(); _inverseMatrix.makeLookAt( _position, _position + _direction, upVec); _matrix.invert(_inverseMatrix); if( _decelerateUpSideRate ) { _upSpeed *= 0.98; _sideSpeed *= 0.98; } if( _decelerateOffsetRate ) { _yawOffsetRate *= 0.98; _pitchOffsetRate *= 0.98; } if( _straightenOffset ) { if( _shift ) { _pitchOffset = 0.0; _yawOffset = 0.0; _pitchOffsetRate = 0.0; _yawOffsetRate = 0.0; } else { _pitchOffsetRate = 0.0; _yawOffsetRate = 0.0; _pitchOffset *= 0.99; _yawOffset *= 0.99; if( fabs(_pitchOffset ) < 0.01 ) _pitchOffset = 0.0; if( fabs(_yawOffset ) < 0.01 ) _pitchOffset = 0.0; } if( _pitchOffset == 0.0 && _yawOffset == 0.0 ) _straightenOffset = false; } } void UFOManipulator::_adjustPosition() { if( !_node.valid() ) return; // Forward line segment at 3 times our intersect distance typedef std::vector Intersections; Intersections intersections; // Check intersects infront. osg::Vec3d ip; if (intersect(_position, _position + (_direction * (_minDistanceInFront * 3.0)), ip )) { double d = (ip - _position).length(); if( d < _minDistanceInFront ) { _position = ip + (_direction * -_minDistanceInFront); _stop(); } } // Check intersects below. osg::CoordinateFrame cf( getCoordinateFrame(_position) ); osg::Vec3d upVec( getUpVector(cf) ); if (intersect(_position, _position - upVec*_minHeightAboveGround*3, ip )) { double d = (ip - _position).length(); if( d < _minHeightAboveGround ) _position = ip + (upVec * _minHeightAboveGround); } } void UFOManipulator::_stop() { _forwardSpeed = 0.0; _sideSpeed = 0.0; _upSpeed = 0.0; _directionRotationRate = 0.0; } void UFOManipulator::getCurrentPositionAsLookAt( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up ) { eye = _position; center = _position + _direction; up.set(getUpVector(getCoordinateFrame(_position))); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/StandardManipulator.cpp0000644000175000017500000006153013151044751025336 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. * * StandardManipulator code Copyright (C) 2010 PCJohn (Jan Peciva) * while some pieces of code were taken from OSG. * Thanks to company Cadwork (www.cadwork.ch) and * Brno University of Technology (www.fit.vutbr.cz) for open-sourcing this work. */ #include #include using namespace osg; using namespace osgGA; using namespace osgUtil; int StandardManipulator::numRelativeFlagsAllocated = 0; int StandardManipulator::allocateRelativeFlag() { return numRelativeFlagsAllocated++; } /// Constructor. StandardManipulator::StandardManipulator( int flags ) : inherited(), _thrown( false ), _allowThrow( true ), _mouseCenterX(0.0f), _mouseCenterY(0.0f), _delta_frame_time(0.01), _last_frame_time(0.0), _modelSize( 0. ), _verticalAxisFixed( true ), _flags( flags ), _relativeFlags( 0 ) { } /// Constructor. StandardManipulator::StandardManipulator( const StandardManipulator& uim, const CopyOp& copyOp ) : osg::Callback(uim, copyOp), inherited( uim, copyOp ), _thrown( uim._thrown ), _allowThrow( uim._allowThrow ), _mouseCenterX(0.0f), _mouseCenterY(0.0f), _ga_t1( dynamic_cast< GUIEventAdapter* >( copyOp( uim._ga_t1.get() ) ) ), _ga_t0( dynamic_cast< GUIEventAdapter* >( copyOp( uim._ga_t0.get() ) ) ), _delta_frame_time(0.01), _last_frame_time(0.0), _modelSize( uim._modelSize ), _verticalAxisFixed( uim._verticalAxisFixed ), _flags( uim._flags ), _relativeFlags( uim._relativeFlags ) { } /** Attach a node to the manipulator. Automatically detaches previously attached node. setNode(NULL) detaches previously attached nodes. Is ignored by manipulators which do not require a reference model.*/ void StandardManipulator::setNode( Node* node ) { _node = node; // update model size if( _node.get() ) { const BoundingSphere& boundingSphere = _node->getBound(); _modelSize = boundingSphere.radius(); } else { _modelSize = 0.; } // compute home position if( getAutoComputeHomePosition() ) computeHomePosition( NULL, ( _flags & COMPUTE_HOME_USING_BBOX ) != 0 ); } /** Return node if attached.*/ const Node* StandardManipulator::getNode() const { return _node.get(); } /** Return node if attached.*/ Node* StandardManipulator::getNode() { return _node.get(); } /** Makes manipulator to keep camera's "UP" vector. * * In general, fixed up vector makes camera control more user friendly. * * To change up vector, use CameraManipulator::setCoordinateFrameCallback.*/ void StandardManipulator::setVerticalAxisFixed( bool value ) { _verticalAxisFixed = value; } /// Sets manipulator animation time when centering on mouse wheel up is enabled. void StandardManipulator::setAnimationTime( const double t ) { if( t <= 0. ) { finishAnimation(); _animationData = NULL; return; } if( !_animationData ) allocAnimationData(); _animationData->_animationTime = t; } /// Returns manipulator animation time when centering on mouse wheel up is enabled. double StandardManipulator::getAnimationTime() const { if( _animationData ) return _animationData->_animationTime; else return 0.; } /// Returns whether manipulator is performing animation at the moment. bool StandardManipulator::isAnimating() const { if( _animationData ) return _animationData->_isAnimating; else return false; } /// Finishes the animation by performing a step that moves it to its final position. void StandardManipulator::finishAnimation() { _thrown = false; if( !isAnimating() ) return; applyAnimationStep( 1., _animationData->_phase ); } /** Move the camera to the default position. The user should probably want to use home(GUIEventAdapter&, GUIActionAdapter&) instead to set manipulator to the home position. This method does not trigger any redraw processing or updates continuous update processing. StandardManipulator implementation only updates its internal structures and recomputes its home position if autoComputeHomePosition is set. Descendant classes are expected to update camera position.*/ void StandardManipulator::home( double /*currentTime*/ ) { if( getAutoComputeHomePosition() ) computeHomePosition( NULL, ( _flags & COMPUTE_HOME_USING_BBOX ) != 0 ); _thrown = false; setTransformation( _homeEye, _homeCenter, _homeUp ); flushMouseEventStack(); } /** Move the camera to the default position. If autoComputeHomePosition is on, home position is computed. The computation considers camera fov and model size and positions camera far enough to fit the model to the screen. StandardManipulator implementation only updates its internal data. If home position is expected to be supported by the descendant manipulator, it has to reimplement the method to update manipulator transformation.*/ void StandardManipulator::home( const GUIEventAdapter& /*ea*/, GUIActionAdapter& us ) { if( getAutoComputeHomePosition() ) { const Camera *camera = us.asView() ? us.asView()->getCamera() : NULL; computeHomePosition( camera, ( _flags & COMPUTE_HOME_USING_BBOX ) != 0 ); } _thrown = false; setTransformation( _homeEye, _homeCenter, _homeUp ); us.requestRedraw(); us.requestContinuousUpdate( false ); flushMouseEventStack(); } /** Start/restart the manipulator.*/ void StandardManipulator::init( const GUIEventAdapter& /*ea*/, GUIActionAdapter& us ) { flushMouseEventStack(); // stop animation _thrown = false; us.requestContinuousUpdate(false); } /** Handles events. Returns true if handled, false otherwise.*/ bool StandardManipulator::handle( const GUIEventAdapter& ea, GUIActionAdapter& us ) { switch( ea.getEventType() ) { case GUIEventAdapter::FRAME: return handleFrame( ea, us ); case GUIEventAdapter::RESIZE: return handleResize( ea, us ); default: break; } if( ea.getHandled() ) return false; switch( ea.getEventType() ) { case GUIEventAdapter::MOVE: return handleMouseMove( ea, us ); case GUIEventAdapter::DRAG: return handleMouseDrag( ea, us ); case GUIEventAdapter::PUSH: return handleMousePush( ea, us ); case GUIEventAdapter::RELEASE: return handleMouseRelease( ea, us ); case GUIEventAdapter::KEYDOWN: return handleKeyDown( ea, us ); case GUIEventAdapter::KEYUP: return handleKeyUp( ea, us ); case GUIEventAdapter::SCROLL: if( _flags & PROCESS_MOUSE_WHEEL ) return handleMouseWheel( ea, us ); else return false; default: return false; } } /// Handles GUIEventAdapter::FRAME event. bool StandardManipulator::handleFrame( const GUIEventAdapter& ea, GUIActionAdapter& us ) { double current_frame_time = ea.getTime(); _delta_frame_time = current_frame_time - _last_frame_time; _last_frame_time = current_frame_time; if( _thrown && performMovement() ) { us.requestRedraw(); } if( _animationData && _animationData->_isAnimating ) { performAnimationMovement( ea, us ); } return false; } /// Handles GUIEventAdapter::RESIZE event. bool StandardManipulator::handleResize( const GUIEventAdapter& ea, GUIActionAdapter& us ) { init( ea, us ); us.requestRedraw(); return true; } /// Handles GUIEventAdapter::MOVE event. bool StandardManipulator::handleMouseMove( const GUIEventAdapter& /*ea*/, GUIActionAdapter& /*us*/ ) { return false; } /// Handles GUIEventAdapter::DRAG event. bool StandardManipulator::handleMouseDrag( const GUIEventAdapter& ea, GUIActionAdapter& us ) { addMouseEvent( ea ); if( performMovement() ) us.requestRedraw(); us.requestContinuousUpdate( false ); _thrown = false; return true; } /// Handles GUIEventAdapter::PUSH event. bool StandardManipulator::handleMousePush( const GUIEventAdapter& ea, GUIActionAdapter& us ) { flushMouseEventStack(); addMouseEvent( ea ); if( performMovement() ) us.requestRedraw(); us.requestContinuousUpdate( false ); _thrown = false; return true; } /// Handles GUIEventAdapter::RELEASE event. bool StandardManipulator::handleMouseRelease( const GUIEventAdapter& ea, GUIActionAdapter& us ) { if( ea.getButtonMask() == 0 ) { double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX; if( timeSinceLastRecordEvent > 0.02 ) flushMouseEventStack(); if( isMouseMoving() ) { if( performMovement() && _allowThrow ) { us.requestRedraw(); us.requestContinuousUpdate( true ); _thrown = true; } return true; } } flushMouseEventStack(); addMouseEvent( ea ); if( performMovement() ) us.requestRedraw(); us.requestContinuousUpdate( false ); _thrown = false; return true; } /// Handles GUIEventAdapter::KEYDOWN event. bool StandardManipulator::handleKeyDown( const GUIEventAdapter& ea, GUIActionAdapter& us ) { if( ea.getKey() == GUIEventAdapter::KEY_Space ) { flushMouseEventStack(); _thrown = false; home(ea,us); return true; } return false; } /// Handles GUIEventAdapter::KEYUP event. bool StandardManipulator::handleKeyUp( const GUIEventAdapter& /*ea*/, GUIActionAdapter& /*us*/ ) { return false; } /// Handles GUIEventAdapter::SCROLL event. bool StandardManipulator::handleMouseWheel( const GUIEventAdapter& /*ea*/, GUIActionAdapter& /*us*/ ) { return false; } /** Get the keyboard and mouse usage of the manipulator.*/ void StandardManipulator::getUsage( ApplicationUsage& usage ) const { usage.addKeyboardMouseBinding( getManipulatorName() + ": Space", "Reset the viewing position to home" ); } /// Make movement step of manipulator. Returns true if any movement was made. bool StandardManipulator::performMovement() { // return if less then two events have been added if( _ga_t0.get() == NULL || _ga_t1.get() == NULL ) return false; // get delta time double eventTimeDelta = _ga_t0->getTime() - _ga_t1->getTime(); if( eventTimeDelta < 0. ) { OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl; eventTimeDelta = 0.; } // get deltaX and deltaY float dx = _ga_t0->getXnormalized() - _ga_t1->getXnormalized(); float dy = _ga_t0->getYnormalized() - _ga_t1->getYnormalized(); // return if there is no movement. if( dx == 0. && dy == 0. ) return false; // call appropriate methods unsigned int buttonMask = _ga_t1->getButtonMask(); if( buttonMask == GUIEventAdapter::LEFT_MOUSE_BUTTON ) { return performMovementLeftMouseButton( eventTimeDelta, dx, dy ); } else if( buttonMask == GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == (GUIEventAdapter::LEFT_MOUSE_BUTTON | GUIEventAdapter::RIGHT_MOUSE_BUTTON) ) { return performMovementMiddleMouseButton( eventTimeDelta, dx, dy ); } else if( buttonMask == GUIEventAdapter::RIGHT_MOUSE_BUTTON ) { return performMovementRightMouseButton( eventTimeDelta, dx, dy ); } return false; } /** Make movement step of manipulator. This method implements movement for left mouse button.*/ bool StandardManipulator::performMovementLeftMouseButton( const double /*eventTimeDelta*/, const double /*dx*/, const double /*dy*/ ) { return false; } /** Make movement step of manipulator. This method implements movement for middle mouse button or combination of left and right mouse button pressed together.*/ bool StandardManipulator::performMovementMiddleMouseButton( const double /*eventTimeDelta*/, const double /*dx*/, const double /*dy*/ ) { return false; } /** Make movement step of manipulator. This method implements movement for right mouse button.*/ bool StandardManipulator::performMovementRightMouseButton( const double /*eventTimeDelta*/, const double /*dx*/, const double /*dy*/ ) { return false; } /// The method processes events for manipulation based on relative mouse movement (mouse delta). bool StandardManipulator::handleMouseDeltaMovement( const GUIEventAdapter& ea, GUIActionAdapter& us ) { float dx = ea.getX() - _mouseCenterX; float dy = ea.getY() - _mouseCenterY; if( dx == 0.f && dy == 0.f ) return false; addMouseEvent( ea ); centerMousePointer( ea, us ); return performMouseDeltaMovement( dx, dy ); } /// The method performs manipulator update based on relative mouse movement (mouse delta). bool StandardManipulator::performMouseDeltaMovement( const float /*dx*/, const float /*dy*/ ) { return false; } /// Makes the manipulator progress in its current animation. bool StandardManipulator::performAnimationMovement( const GUIEventAdapter& ea, GUIActionAdapter& us ) { double f = (ea.getTime() - _animationData->_startTime) / _animationData->_animationTime; if( f >= 1. ) { f = 1.; _animationData->_isAnimating = false; if( !_thrown ) us.requestContinuousUpdate( false ); } applyAnimationStep( f, _animationData->_phase ); _animationData->_phase = f; us.requestRedraw(); return _animationData->_isAnimating; } /// Updates manipulator by a single animation step void StandardManipulator::applyAnimationStep( const double /*currentProgress*/, const double /*prevProgress*/ ) { } /// Centers mouse pointer void StandardManipulator::centerMousePointer( const GUIEventAdapter& ea, GUIActionAdapter& us ) { _mouseCenterX = (ea.getXmin() + ea.getXmax()) / 2.0f; _mouseCenterY = (ea.getYmin() + ea.getYmax()) / 2.0f; us.requestWarpPointer( _mouseCenterX, _mouseCenterY ); } /** Add the current mouse GUIEvent to internal stack.*/ void StandardManipulator::addMouseEvent( const GUIEventAdapter& ea ) { _ga_t1 = _ga_t0; _ga_t0 = &ea; } /** Reset the internal GUIEvent stack.*/ void StandardManipulator::flushMouseEventStack() { _ga_t1 = NULL; _ga_t0 = NULL; } /** Check the speed at which the mouse is moving. If speed is below a threshold then return false, otherwise return true.*/ bool StandardManipulator::isMouseMoving() const { if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; static const float velocity = 0.1f; float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); float len = sqrtf(dx*dx+dy*dy); float dt = _ga_t0->getTime()-_ga_t1->getTime(); return (len>dt*velocity); } /** Set the 'allow throw' flag. If it is set to true (default), releasing the mouse button while moving the mouse results in a throw. If manipulator was thrown, it continues spinning although no mouse button is down at the moment.*/ void StandardManipulator::setAllowThrow( bool allowThrow ) { _allowThrow = allowThrow; } /** Returns the scale that should be applied on animation of "thrown" manipulator state to avoid its dependency on varying frame rate. eventTimeDelta parameter gives the time difference between last two events that started the animation.*/ float StandardManipulator::getThrowScale( const double eventTimeDelta ) const { if( _thrown ) { if (eventTimeDelta == 0.f) return 0.f; return float( _delta_frame_time / eventTimeDelta ); } else return 1.f; } /** Update rotation by yaw and pitch. * * localUp parameter defines either camera's "UP" vector * that will be preserved during rotation, or it can be zero (0,0,0) to specify * that camera's "UP" vector will be not preserved and free rotation will be made.*/ void StandardManipulator::rotateYawPitch( Quat& rotation, const double yaw, const double pitch, const Vec3d& localUp ) { bool verticalAxisFixed = (localUp != Vec3d( 0.,0.,0. )); // fix current rotation if( verticalAxisFixed ) fixVerticalAxis( rotation, localUp, true ); // rotations Quat rotateYaw( -yaw, verticalAxisFixed ? localUp : rotation * Vec3d( 0.,1.,0. ) ); Quat rotatePitch; Quat newRotation; Vec3d cameraRight( rotation * Vec3d( 1.,0.,0. ) ); double my_dy = pitch; int i = 0; do { // rotations rotatePitch.makeRotate( my_dy, cameraRight ); newRotation = rotation * rotateYaw * rotatePitch; // update vertical axis if( verticalAxisFixed ) fixVerticalAxis( newRotation, localUp, false ); // check for viewer's up vector to be more than 90 degrees from "up" axis Vec3d newCameraUp = newRotation * Vec3d( 0.,1.,0. ); if( newCameraUp * localUp > 0. ) { // apply new rotation rotation = newRotation; return; } my_dy /= 2.; if( ++i == 20 ) { rotation = rotation * rotateYaw; return; } } while( true ); } /** The method corrects the rotation to make impression of fixed up direction. * Technically said, it makes the roll component of the rotation equal to zero. * * Up vector is given by CoordinateFrame and it is +z by default. * It can be changed by osgGA::CameraManipulator::setCoordinateFrameCallback(). * * Eye parameter is user position, rotation is the rotation to be fixed, and * disallowFlipOver, when set on true, avoids pitch rotation component to grow * over +/- 90 degrees. If this happens and disallowFlipOver is true, * manipulator is rotated by 180 degrees. More precisely, roll rotation component is changed by 180 degrees, * making pitch once again between -90..+90 degrees limits.*/ void StandardManipulator::fixVerticalAxis( Vec3d& eye, Quat& rotation, bool disallowFlipOver ) { CoordinateFrame coordinateFrame = getCoordinateFrame( eye ); Vec3d localUp = getUpVector( coordinateFrame ); fixVerticalAxis( rotation, localUp, disallowFlipOver ); } /** The method corrects the rotation to make impression of fixed up direction. * Technically said, it makes the roll component of the rotation equal to zero. * * rotation parameter is the rotation to be fixed. * localUp is UP vector and must not be zero length. * disallowFlipOver, when set on true, avoids pitch rotation component to grow * over +/- 90 degrees. If this happens and disallowFlipOver is true, * manipulator is rotated by 180 degrees. More precisely, roll rotation component is changed by 180 degrees, * making pitch once again between -90..+90 degrees limits.*/ void StandardManipulator::fixVerticalAxis( Quat& rotation, const Vec3d& localUp, bool disallowFlipOver ) { // camera direction vectors Vec3d cameraUp = rotation * Vec3d( 0.,1.,0. ); Vec3d cameraRight = rotation * Vec3d( 1.,0.,0. ); Vec3d cameraForward = rotation * Vec3d( 0.,0.,-1. ); // computed directions Vec3d newCameraRight1 = cameraForward ^ localUp; Vec3d newCameraRight2 = cameraUp ^ localUp; Vec3d newCameraRight = (newCameraRight1.length2() > newCameraRight2.length2()) ? newCameraRight1 : newCameraRight2; if( newCameraRight * cameraRight < 0. ) newCameraRight = -newCameraRight; // vertical axis correction Quat rotationVerticalAxisCorrection; rotationVerticalAxisCorrection.makeRotate( cameraRight, newCameraRight ); // rotate camera rotation *= rotationVerticalAxisCorrection; if( disallowFlipOver ) { // make viewer's up vector to be always less than 90 degrees from "up" axis Vec3d newCameraUp = newCameraRight ^ cameraForward; if( newCameraUp * localUp < 0. ) rotation = Quat( PI, Vec3d( 0.,0.,1. ) ) * rotation; } } /** The method corrects the rotation to make impression of fixed up direction. * Technically said, it makes the roll component of the rotation equal to zero. * * forward and up parameters are the forward and up vectors of the manipulator. * newUp will receive corrected UP manipulator vector. localUp is UP vector * that is used for vertical correction. * disallowFlipOver when set on true avoids pitch rotation component to grow * over +/- 90 degrees. If this happens and disallowFlipOver is true, * right and up camera vectors are negated (changing roll by 180 degrees), * making pitch once again between -90..+90 degrees limits.*/ void StandardManipulator::fixVerticalAxis( const osg::Vec3d& forward, const osg::Vec3d& up, osg::Vec3d& newUp, const osg::Vec3d& localUp, bool /*disallowFlipOver*/ ) { // right direction osg::Vec3d right1 = forward ^ localUp; osg::Vec3d right2 = up ^ localUp; osg::Vec3d right = (right1.length2() > right2.length2()) ? right1 : right2; // updatedUp osg::Vec3d updatedUp = right ^ forward; if( updatedUp.normalize() >= 0. ) // return updatedUp newUp = updatedUp; else { // return original up OSG_WARN << "StandardManipulator::fixVerticalAxis warning: Can not update vertical axis." << std::endl; newUp = up; } } /** The method sends a ray into the scene and the point of the closest intersection is used to set a new center for the manipulator. For Orbit-style manipulators, the orbiting center is set. For FirstPerson-style manipulators, view is pointed towards the center.*/ bool StandardManipulator::setCenterByMousePointerIntersection( const GUIEventAdapter& ea, GUIActionAdapter& us ) { osg::View* view = us.asView(); if( !view ) return false; Camera *camera = view->getCamera(); if( !camera ) return false; // prepare variables float x = ( ea.getX() - ea.getXmin() ) / ( ea.getXmax() - ea.getXmin() ); float y = ( ea.getY() - ea.getYmin() ) / ( ea.getYmax() - ea.getYmin() ); LineSegmentIntersector::CoordinateFrame cf; Viewport *vp = camera->getViewport(); if( vp ) { cf = Intersector::WINDOW; x *= vp->width(); y *= vp->height(); } else cf = Intersector::PROJECTION; // perform intersection computation ref_ptr< LineSegmentIntersector > picker = new LineSegmentIntersector( cf, x, y ); IntersectionVisitor iv( picker.get() ); camera->accept( iv ); // return on no intersections if( !picker->containsIntersections() ) return false; // get all intersections LineSegmentIntersector::Intersections& intersections = picker->getIntersections(); // get current transformation osg::Vec3d eye, oldCenter, up; getTransformation( eye, oldCenter, up ); // new center osg::Vec3d newCenter = (*intersections.begin()).getWorldIntersectPoint(); // make vertical axis correction if( getVerticalAxisFixed() ) { CoordinateFrame coordinateFrame = getCoordinateFrame( newCenter ); Vec3d localUp = getUpVector( coordinateFrame ); fixVerticalAxis( newCenter - eye, up, up, localUp, true ); } // set the new center setTransformation( eye, newCenter, up ); // warp pointer // note: this works for me on standard camera on GraphicsWindowEmbedded and Qt, // while it was necessary to implement requestWarpPointer like follows: // // void QOSGWidget::requestWarpPointer( float x, float y ) // { // osgViewer::Viewer::requestWarpPointer( x, y ); // QCursor::setPos( this->mapToGlobal( QPoint( int( x+.5f ), int( y+.5f ) ) ) ); // } // // Additions of .5f are just for the purpose of rounding. centerMousePointer( ea, us ); return true; } /** Makes mouse pointer intersection test with the geometry bellow the pointer and starts animation to center camera to look at the closest hit bellow the mouse pointer. If there is a hit, animation is started and true is returned. Otherwise, the method returns false.*/ bool StandardManipulator::startAnimationByMousePointerIntersection( const osgGA::GUIEventAdapter& /*ea*/, osgGA::GUIActionAdapter& /*us*/ ) { return false; } StandardManipulator::AnimationData::AnimationData() :_isAnimating( false ) { } void StandardManipulator::AnimationData::start( const double startTime ) { _isAnimating = true; _startTime = startTime; _phase = 0.; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/GUIEventHandler.cpp0000644000175000017500000000256313151044751024307 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgGA; GUIEventHandler::~GUIEventHandler() { } // adapt EventHandler usage to old style GUIEventHandler usage bool GUIEventHandler::handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv) { osgGA::EventVisitor* ev = dynamic_cast(nv); osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter(); if (ea && ev && ev->getActionAdapter()) { #if 1 bool handled = handle(*ea, *(ev->getActionAdapter()), object, nv); if (handled) ea->setHandled(true); return handled; #else return handleWithCheckAgainstIgnoreHandledEventsMask(*ea, *(ev->getActionAdapter()), object, nv); #endif } return false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/StateSetManipulator.cpp0000644000175000017500000001710113151044751025325 0ustar albertoalberto#include #include #include #include #include #include #include // #define COMPILE_TEXENVFILTER_USAGE #if COMPILE_TEXENVFILTER_USAGE #include #endif using namespace osg; using namespace osgGA; StateSetManipulator::StateSetManipulator(osg::StateSet* stateset): _initialized(false), _backface(false), _lighting(false), _texture(false), _maxNumOfTextureUnits(4), _keyEventToggleBackfaceCulling('b'), _keyEventToggleLighting('l'), _keyEventToggleTexturing('t'), _keyEventCyclePolygonMode('w') { setStateSet(stateset); } StateSetManipulator::~StateSetManipulator() { } void StateSetManipulator::setStateSet(StateSet *stateset) { _stateset = stateset; #if 0 // specify that this stateset is dynamic so it prevents // the draw and update phase from overlapping - good for // stability but breaks all the performance advantage of // DrawThreadPerContext. _stateset->setDataVariance(osg::Object::DYNAMIC); #endif } StateSet *StateSetManipulator::getStateSet() { return _stateset.get(); } const StateSet *StateSetManipulator::getStateSet() const { return _stateset.get(); } void StateSetManipulator::clone() { if (!_stateset) return; // we clone the StateSet so that any draw traversals that might be running at the time of the // event traversal won't change the same StateSet that is being read. One could just set the // DataVariance to DYNAMIC to avoid this overlap, but this would introduce a performance penalty. StateSet::ParentList parents = _stateset->getParents(); osg::ref_ptr newStateSet = dynamic_cast(_stateset->clone(osg::CopyOp::SHALLOW_COPY)); // change the parents of the original StateSet to point to the new stateset for(StateSet::ParentList::iterator itr = parents.begin(); itr != parents.end(); ++itr) { osg::Node* node = *itr; node->setStateSet(newStateSet.get()); } _stateset = newStateSet; } bool StateSetManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa) { if(!_stateset.valid()) return false; if (!_initialized) { _initialized = true; _backface = (_stateset->getMode(GL_CULL_FACE)&osg::StateAttribute::ON); _lighting =(_stateset->getMode(GL_LIGHTING)&osg::StateAttribute::ON); unsigned int mode = osg::StateAttribute::INHERIT|osg::StateAttribute::ON; _texture = (_stateset->getTextureMode(0,GL_TEXTURE_2D)&mode)!=0 || (_stateset->getTextureMode(0,GL_TEXTURE_3D)&mode)!=0 || (_stateset->getTextureMode(0,GL_TEXTURE_RECTANGLE)&mode)!=0 || (_stateset->getTextureMode(0,GL_TEXTURE_CUBE_MAP)&mode)!=0; #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) _texture |= ((_stateset->getTextureMode(0,GL_TEXTURE_1D)&mode)!=0); #endif } if (ea.getHandled()) return false; if (ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN) { if ( ea.getKey() == _keyEventToggleBackfaceCulling ) { setBackfaceEnabled(!getBackfaceEnabled()); aa.requestRedraw(); return true; } if ( ea.getKey() == _keyEventToggleLighting ) { setLightingEnabled(!getLightingEnabled()); aa.requestRedraw(); return true; } if ( ea.getKey() == _keyEventToggleTexturing ) { setTextureEnabled(!getTextureEnabled()); aa.requestRedraw(); return true; } if ( ea.getKey() == _keyEventCyclePolygonMode ) { cyclePolygonMode(); aa.requestRedraw(); return true; } } return false; } void StateSetManipulator::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding(reinterpret_cast(&_keyEventToggleBackfaceCulling),"Toggle backface culling"); usage.addKeyboardMouseBinding(reinterpret_cast(&_keyEventToggleLighting),"Toggle lighting"); usage.addKeyboardMouseBinding(reinterpret_cast(&_keyEventToggleTexturing),"Toggle texturing"); usage.addKeyboardMouseBinding(reinterpret_cast(&_keyEventCyclePolygonMode),"Toggle polygon fill mode between fill, line (wire frame) and points"); } void StateSetManipulator::setBackfaceEnabled(bool newbackface) { if (_backface == newbackface) return; clone(); _backface = newbackface; if( _backface ) _stateset->setMode(GL_CULL_FACE,osg::StateAttribute::ON); else _stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); } void StateSetManipulator::setLightingEnabled(bool newlighting) { if (_lighting == newlighting) return; clone(); _lighting = newlighting; if( _lighting ) _stateset->setMode(GL_LIGHTING,osg::StateAttribute::ON); else _stateset->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); } void StateSetManipulator::setTextureEnabled(bool newtexture) { if (_texture==newtexture) return; clone(); _texture = newtexture; // osg::ref_ptr< osg::Texture > tex = dynamic_cast // ( _stateset->getAttribute( osg::StateAttribute::TEXTURE ) ); // cout << tex->numTextureUnits() << endl; unsigned int mode = osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF; if ( _texture ) mode = osg::StateAttribute::INHERIT|osg::StateAttribute::ON; for( unsigned int ii=0; ii<_maxNumOfTextureUnits; ii++ ) { #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) _stateset->setTextureMode( ii, GL_TEXTURE_1D, mode ); #endif _stateset->setTextureMode( ii, GL_TEXTURE_2D, mode ); _stateset->setTextureMode( ii, GL_TEXTURE_3D, mode ); _stateset->setTextureMode( ii, GL_TEXTURE_RECTANGLE, mode ); _stateset->setTextureMode( ii, GL_TEXTURE_CUBE_MAP, mode); } } void StateSetManipulator::setPolygonMode(osg::PolygonMode::Mode newpolygonmode) { clone(); osg::PolygonMode* polyModeObj = getOrCreatePolygonMode(); polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK,newpolygonmode); } void StateSetManipulator::cyclePolygonMode() { clone(); osg::PolygonMode* polyModeObj = getOrCreatePolygonMode(); osg::PolygonMode::Mode currentMode = getPolygonMode(); // cycle through the available modes. switch(currentMode) { case osg::PolygonMode::FILL : polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE); break; case osg::PolygonMode::LINE : polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::POINT); break; case osg::PolygonMode::POINT : polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::FILL); break; } } osg::PolygonMode::Mode StateSetManipulator::getPolygonMode() const { osg::PolygonMode* polyModeObj = dynamic_cast(_stateset->getAttribute(osg::StateAttribute::POLYGONMODE)); if (polyModeObj) return polyModeObj->getMode(osg::PolygonMode::FRONT_AND_BACK); else return osg::PolygonMode::FILL; } osg::PolygonMode* StateSetManipulator::getOrCreatePolygonMode() { osg::PolygonMode* polyModeObj = dynamic_cast(_stateset->getAttribute(osg::StateAttribute::POLYGONMODE)); if (!polyModeObj) { polyModeObj = new osg::PolygonMode; _stateset->setAttribute(polyModeObj); } return polyModeObj; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/Device.cpp0000644000175000017500000000233213151044751022554 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include using namespace osgGA; Device::Device() : osg::Object() , _capabilities(UNKNOWN) { setEventQueue(new EventQueue); } Device::Device(const Device& es, const osg::CopyOp& copyop): osg::Object(es,copyop) { setEventQueue(new EventQueue); } void Device::sendEvent(const Event& /*event*/) { OSG_WARN << "Device::sendEvent not implemented!" << std::endl; } void Device::sendEvents(const EventQueue::Events& events) { for(EventQueue::Events::const_iterator i = events.begin(); i != events.end(); i++) { sendEvent(**i); } } Device::~Device() { } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/Widget.cpp0000644000175000017500000002225413151044751022605 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include using namespace osgGA; Widget::Widget(): _focusBehaviour(FOCUS_FOLLOWS_POINTER), _hasEventFocus(false), _graphicsInitialized(false) { setNumChildrenRequiringEventTraversal(1); } Widget::Widget(const Widget& widget, const osg::CopyOp& copyop): osg::Group(), _focusBehaviour(widget._focusBehaviour), _hasEventFocus(false), _graphicsInitialized(false) { setNumChildrenRequiringEventTraversal(1); } void Widget::setExtents(const osg::BoundingBoxf& bb) { _extents = bb; } void Widget::updateFocus(osg::NodeVisitor& nv) { osgGA::EventVisitor* ev = dynamic_cast(&nv); osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0; if (ev && aa) { osgGA::EventQueue::Events& events = ev->getEvents(); for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter(); if (ea) { bool previousFocus = _hasEventFocus; if (_focusBehaviour==CLICK_TO_FOCUS) { if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH) { int numButtonsPressed = 0; if (ea->getButtonMask()&osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) ++numButtonsPressed; if (ea->getButtonMask()&osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) ++numButtonsPressed; if (ea->getButtonMask()&osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ++numButtonsPressed; if (numButtonsPressed==1) { osgUtil::LineSegmentIntersector::Intersections intersections; bool withinWidget = aa->computeIntersections(*ea, nv.getNodePath(), intersections); if (withinWidget) _hasEventFocus = true; else _hasEventFocus = false; } } } else if (_focusBehaviour==FOCUS_FOLLOWS_POINTER) { bool checkWithinWidget = false; if (!_hasEventFocus) { checkWithinWidget = (ea->getEventType()!=osgGA::GUIEventAdapter::FRAME) && ea->getButtonMask()==0; } else { // if mouse move or mouse release check to see if mouse still within widget to retain focus if (ea->getEventType()==osgGA::GUIEventAdapter::MOVE) { checkWithinWidget = true; } else if (ea->getEventType()==osgGA::GUIEventAdapter::RELEASE) { // if no buttons pressed then check if (ea->getButtonMask()==0) checkWithinWidget = true; } } if (checkWithinWidget) { osgUtil::LineSegmentIntersector::Intersections intersections; bool withinWidget = aa->computeIntersections(*ea, nv.getNodePath(), intersections); _hasEventFocus = withinWidget; } } if (previousFocus != _hasEventFocus) { if (_hasEventFocus) { enter(); #if 0 if (view->getCameraManipulator()) { view->getCameraManipulator()->finishAnimation(); view->requestContinuousUpdate( false ); } #endif } else { leave(); } } } } } } void Widget::setHasEventFocus(bool focus) { if (_hasEventFocus == focus) return; _hasEventFocus = focus; if (_hasEventFocus) enter(); else leave(); } bool Widget::getHasEventFocus() const { return _hasEventFocus; } void Widget::enter() { osg::CallbackObject* co = osg::getCallbackObject(this, "enter"); if (co) { co->run(this); } else { enterImplementation(); } } void Widget::enterImplementation() { OSG_NOTICE<<"enter()"<run(this); } else { leaveImplementation(); } } void Widget::leaveImplementation() { OSG_NOTICE<<"leave()"<run(this, inputParameters, outputParameters); } else { traverseImplementation(nv); } } void Widget::traverseImplementation(osg::NodeVisitor& nv) { if (!_graphicsInitialized && nv.getVisitorType()!=osg::NodeVisitor::CULL_VISITOR) createGraphics(); osgGA::EventVisitor* ev = dynamic_cast(&nv); if (ev) { updateFocus(nv); if (getHasEventFocus()) { // signify that event has been taken by widget with focus ev->setEventHandled(true); osgGA::EventQueue::Events& events = ev->getEvents(); for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { if (handle(ev, itr->get())) { (*itr)->setHandled(true); } } } } else { osg::Group::traverse(nv); } } bool Widget::handle(osgGA::EventVisitor* ev, osgGA::Event* event) { osg::CallbackObject* co = osg::getCallbackObject(this, "handle"); if (co) { // currently lua scripting takes a ref count so messes up handling of NodeVisitor's created on stack, // so don't attempt to call the sctipt. if (ev->referenceCount()==0) { return handleImplementation(ev, event); } osg::Parameters inputParameters, outputParameters; inputParameters.push_back(ev); inputParameters.push_back(event); if (co->run(this, inputParameters, outputParameters)) { if (outputParameters.size()>=1) { osg::BoolValueObject* bvo = dynamic_cast(outputParameters[0].get()); if (bvo) { return bvo->getValue(); } return false; } } return false; } else { return handleImplementation(ev, event); } } bool Widget::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event) { return false; } bool Widget::computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const { osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0; osgUtil::LineSegmentIntersector::Intersections intersections; if (aa && aa->computeIntersections(*event, ev->getNodePath(), intersections)) { localPosition = intersections.begin()->getLocalIntersectPoint(); return (_extents.contains(localPosition, 1e-6)); } else { return false; } } void Widget::createGraphics() { osg::CallbackObject* co = osg::getCallbackObject(this, "createGraphics"); if (co) { co->run(this); } else { createGraphicsImplementation(); } } void Widget::createGraphicsImplementation() { _graphicsInitialized = true; } osg::BoundingSphere Widget::computeBound() const { if (_extents.valid()) return osg::BoundingSphere(_extents); else return osg::Group::computeBound(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/TrackballManipulator.cpp0000644000175000017500000000201513151044751025466 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include using namespace osg; using namespace osgGA; /// Constructor. TrackballManipulator::TrackballManipulator( int flags ) : inherited( flags ) { setVerticalAxisFixed( false ); } /// Constructor. TrackballManipulator::TrackballManipulator( const TrackballManipulator& tm, const CopyOp& copyOp ) : osg::Callback(tm, copyOp), inherited( tm, copyOp ) { } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/CameraViewSwitchManipulator.cpp0000644000175000017500000000600213151044751026774 0ustar albertoalberto#include #include #include #include using namespace osg; using namespace osgGA; class CollectCameraViewsNodeVisitor : public osg::NodeVisitor { public: CollectCameraViewsNodeVisitor(CameraViewSwitchManipulator::CameraViewList* cameraViews): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _cameraViews(cameraViews) {} virtual void apply(CameraView& node) { _cameraViews->push_back(&node); } CameraViewSwitchManipulator::CameraViewList* _cameraViews; }; void CameraViewSwitchManipulator::setNode(osg::Node* node) { _node = node; _cameraViews.clear(); CollectCameraViewsNodeVisitor visitor(&_cameraViews); _node->accept(visitor); } void CameraViewSwitchManipulator::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding("CameraViewSwitcher: [","Decrease current camera number"); usage.addKeyboardMouseBinding("CameraViewSwitcher: ]","Increase current camera number"); } bool CameraViewSwitchManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter&) { if (ea.getHandled()) return false; switch(ea.getEventType()) { case(GUIEventAdapter::KEYDOWN): if (ea.getKey()=='[') { if (_currentView == 0) _currentView = _cameraViews.size()-1; else _currentView--; return true; } else if (ea.getKey()==']') { _currentView++; if (_currentView >= _cameraViews.size()) _currentView = 0; return true; } return false; default: return false; } } osg::Matrixd CameraViewSwitchManipulator::getMatrix() const { osg::Matrix mat; if (_currentView < _cameraViews.size()) { NodePathList parentNodePaths = _cameraViews[_currentView]->getParentalNodePaths(); if (!parentNodePaths.empty()) { mat = osg::computeLocalToWorld(parentNodePaths[0]); // TODO take into account the position and attitude of the CameraView } else { OSG_NOTICE<<"CameraViewSwitchManipulator::getMatrix(): Unable to calculate matrix due to empty parental path."<getParentalNodePaths(); if (!parentNodePaths.empty()) { mat = osg::computeWorldToLocal(parentNodePaths[0]); // TODO take into account the position and attitude of the CameraView } else { OSG_NOTICE<<"CameraViewSwitchManipulator::getInverseMatrix(): Unable to calculate matrix due to empty parental path."< using namespace osgGA; osg::ref_ptr& GUIEventAdapter::getAccumulatedEventState() { static osg::ref_ptr s_eventState = new GUIEventAdapter; return s_eventState; } GUIEventAdapter::GUIEventAdapter(): _eventType(NONE), _windowX(0), _windowY(0), _windowWidth(1280), _windowHeight(1024), _key(0), _unmodifiedKey(0), _button(0), _Xmin(-1.0), _Xmax(1.0), _Ymin(-1.0), _Ymax(1.0), _mx(0.0), _my(0.0), _buttonMask(0), _modKeyMask(0), _mouseYOrientation(Y_INCREASING_DOWNWARDS), _scrolling(), _tabletPen(), _touchData(NULL) {} GUIEventAdapter::GUIEventAdapter(const GUIEventAdapter& rhs,const osg::CopyOp& copyop): osgGA::Event(rhs,copyop), _eventType(rhs._eventType), _context(rhs._context), _windowX(rhs._windowX), _windowY(rhs._windowY), _windowWidth(rhs._windowWidth), _windowHeight(rhs._windowHeight), _key(rhs._key), _unmodifiedKey(rhs._unmodifiedKey), _button(rhs._button), _Xmin(rhs._Xmin), _Xmax(rhs._Xmax), _Ymin(rhs._Ymin), _Ymax(rhs._Ymax), _mx(rhs._mx), _my(rhs._my), _buttonMask(rhs._buttonMask), _modKeyMask(rhs._modKeyMask), _mouseYOrientation(rhs._mouseYOrientation), _scrolling(rhs._scrolling), _tabletPen(rhs._tabletPen), _touchData(NULL) { if(TouchData* td = rhs.getTouchData()) setTouchData(osg::clone(td, copyop)); } GUIEventAdapter::~GUIEventAdapter() { } void GUIEventAdapter::setWindowRectangle(int x, int y, int width, int height, bool updateMouseRange) { _windowX = x; _windowY = y; _windowWidth = width; _windowHeight = height; if (updateMouseRange) { setInputRange(0, 0, width, height); } } void GUIEventAdapter::setInputRange(float Xmin, float Ymin, float Xmax, float Ymax) { _Xmin = Xmin; _Ymin = Ymin; _Xmax = Xmax; _Ymax = Ymax; } const osg::Matrix GUIEventAdapter::getPenOrientation() const { float xRad = osg::DegreesToRadians ( getPenTiltY() ); float yRad = osg::DegreesToRadians ( getPenTiltX() ); float zRad = osg::DegreesToRadians ( getPenRotation() ); osg::Matrix xrot = osg::Matrix::rotate ( xRad, osg::Vec3f(1.0f, 0.0f, 0.0f) ); osg::Matrix yrot = osg::Matrix::rotate ( yRad, osg::Vec3f(0.0f, 0.0f, 1.0f) ); osg::Matrix zrot = osg::Matrix::rotate ( zRad, osg::Vec3f(0.0f, 1.0f, 0.0f) ); return ( zrot * yrot * xrot ); } void GUIEventAdapter::addTouchPoint(unsigned int id, TouchPhase phase, float x, float y, unsigned int tapCount) { if (!_touchData.valid()) { _touchData = new TouchData(); setX(x); setY(y); } _touchData->addTouchPoint(id, phase, x, y, tapCount); } void GUIEventAdapter::copyPointerDataFrom(const osgGA::GUIEventAdapter& sourceEvent) { setGraphicsContext(const_cast(sourceEvent.getGraphicsContext())); setX(sourceEvent.getX()); setY(sourceEvent.getY()); setInputRange(sourceEvent.getXmin(), sourceEvent.getYmin(), sourceEvent.getXmax(), sourceEvent.getYmax()); setButtonMask(sourceEvent.getButtonMask()); setMouseYOrientation(sourceEvent.getMouseYOrientation()); setPointerDataList(sourceEvent.getPointerDataList()); } void GUIEventAdapter::setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::MouseYOrientation myo) { if ( myo==_mouseYOrientation ) return; setMouseYOrientation( myo ); _my = _Ymax - _my + _Ymin; if( isMultiTouchEvent() ) { for( TouchData::iterator itr = getTouchData()->begin(); itr != getTouchData()->end(); itr++ ) itr->y = _Ymax - itr->y + _Ymin; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/EventVisitor.cpp0000644000175000017500000000227613151044751024025 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osg; using namespace osgGA; EventVisitor::EventVisitor() : NodeVisitor(EVENT_VISITOR,TRAVERSE_ACTIVE_CHILDREN), _handled(false) { } EventVisitor::~EventVisitor() { } void EventVisitor::addEvent(Event* event) { _events.push_back(event); } void EventVisitor::removeEvent(Event* event) { EventQueue::Events::iterator itr = std::find(_events.begin(), _events.end(), event); if (itr!=_events.end()) _events.erase(itr); } void EventVisitor::reset() { _events.clear(); _handled = false; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/AnimationPathManipulator.cpp0000644000175000017500000001251313151044751026327 0ustar albertoalberto#include #include using namespace osgGA; AnimationPathManipulator::AnimationPathManipulator(osg::AnimationPath* animationPath) { _printOutTimingInfo = true; _animationPath = animationPath; _timeOffset = 0.0; _timeScale = 1.0; _isPaused = false; _realStartOfTimedPeriod = 0.0; _animStartOfTimedPeriod = 0.0; _numOfFramesSinceStartOfTimedPeriod = -1; // need to init. } AnimationPathManipulator::AnimationPathManipulator( const std::string& filename ) { _printOutTimingInfo = true; _animationPath = new osg::AnimationPath; _animationPath->setLoopMode(osg::AnimationPath::LOOP); _timeOffset = 0.0; _timeScale = 1.0; _isPaused = false; osgDB::ifstream in(filename.c_str()); if (!in) { OSG_WARN << "AnimationPathManipulator: Cannot open animation path file \"" << filename << "\".\n"; _valid = false; return; } _animationPath->read(in); in.close(); } void AnimationPathManipulator::home(double currentTime) { if (_animationPath.valid()) { _timeOffset = _animationPath->getFirstTime()-currentTime; } // reset the timing of the animation. _numOfFramesSinceStartOfTimedPeriod=-1; } void AnimationPathManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter&) { home(ea.getTime()); } void AnimationPathManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& aa) { home(ea,aa); } bool AnimationPathManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us) { if( !valid() ) return false; switch( ea.getEventType() ) { case GUIEventAdapter::FRAME: if( _isPaused ) { handleFrame( _pauseTime ); } else { handleFrame( ea.getTime() ); } return false; case GUIEventAdapter::KEYDOWN: if (ea.getKey()==' ') { _isPaused = false; home(ea,us); us.requestRedraw(); us.requestContinuousUpdate(false); return true; } else if (ea.getKey()==')') { double time = _isPaused ? _pauseTime : ea.getTime(); double animationTime = (time+_timeOffset)*_timeScale; _timeScale *= 1.1; OSG_NOTICE<<"Animation speed = "<<_timeScale*100<<"%"<getInterpolatedControlPoint( animTime, cp ); if (_numOfFramesSinceStartOfTimedPeriod==-1) { _realStartOfTimedPeriod = time; _animStartOfTimedPeriod = animTime; } ++_numOfFramesSinceStartOfTimedPeriod; double animDelta = (animTime-_animStartOfTimedPeriod); if (animDelta>=_animationPath->getPeriod()) { if (_animationCompletedCallback.valid()) { _animationCompletedCallback->completed(this); } if (_printOutTimingInfo) { double delta = time-_realStartOfTimedPeriod; double frameRate = (double)_numOfFramesSinceStartOfTimedPeriod/delta; OSG_NOTICE <<"AnimatonPath completed in "<getParentalNodePaths(); if (!nodePaths.empty()) { if (nodePaths.size()>1) { OSG_NOTICE<<"osgGA::NodeTrackerManipualtor::setTrackNode(..) taking first parent path, ignoring others."<className()<getName()<<"): Path set"<getBound(); setHomePosition(boundingSphere._center+osg::Vec3d( 0.0,-3.5f * boundingSphere._radius,0.0f), boundingSphere._center, osg::Vec3d(0.0f,0.0f,1.0f), _autoComputeHomePosition); } } void NodeTrackerManipulator::setByMatrix(const osg::Matrixd& matrix) { osg::Vec3d eye,center,up; matrix.getLookAt(eye,center,up,_distance); computePosition(eye,center,up); } void NodeTrackerManipulator::computeNodeWorldToLocal(osg::Matrixd& worldToLocal) const { osg::NodePath nodePath; if (_trackNodePath.getNodePath(nodePath)) { worldToLocal = osg::computeWorldToLocal(nodePath); } } void NodeTrackerManipulator::computeNodeLocalToWorld(osg::Matrixd& localToWorld) const { osg::NodePath nodePath; if (_trackNodePath.getNodePath(nodePath)) { localToWorld = osg::computeLocalToWorld(nodePath); } } void NodeTrackerManipulator::computeNodeCenterAndRotation(osg::Vec3d& nodeCenter, osg::Quat& nodeRotation) const { osg::Matrixd localToWorld, worldToLocal; computeNodeLocalToWorld(localToWorld); computeNodeWorldToLocal(worldToLocal); osg::NodePath nodePath; if (_trackNodePath.getNodePath(nodePath) && !nodePath.empty()) nodeCenter = osg::Vec3d(nodePath.back()->getBound().center())*localToWorld; else nodeCenter = osg::Vec3d(0.0f,0.0f,0.0f)*localToWorld; switch(_trackerMode) { case(NODE_CENTER_AND_AZIM): { CoordinateFrame coordinateFrame = getCoordinateFrame(nodeCenter); osg::Matrixd localToFrame(localToWorld*osg::Matrixd::inverse(coordinateFrame)); double azim = atan2(-localToFrame(0,1),localToFrame(0,0)); osg::Quat nodeRotationRelToFrame, rotationOfFrame; nodeRotationRelToFrame.makeRotate(-azim,0.0,0.0,1.0); rotationOfFrame = coordinateFrame.getRotate(); nodeRotation = nodeRotationRelToFrame*rotationOfFrame; break; } case(NODE_CENTER_AND_ROTATION): { // scale the matrix to get rid of any scales before we extract the rotation. double sx = 1.0/sqrt(localToWorld(0,0)*localToWorld(0,0) + localToWorld(1,0)*localToWorld(1,0) + localToWorld(2,0)*localToWorld(2,0)); double sy = 1.0/sqrt(localToWorld(0,1)*localToWorld(0,1) + localToWorld(1,1)*localToWorld(1,1) + localToWorld(2,1)*localToWorld(2,1)); double sz = 1.0/sqrt(localToWorld(0,2)*localToWorld(0,2) + localToWorld(1,2)*localToWorld(1,2) + localToWorld(2,2)*localToWorld(2,2)); localToWorld = localToWorld*osg::Matrixd::scale(sx,sy,sz); nodeRotation = localToWorld.getRotate(); break; } case(NODE_CENTER): default: { CoordinateFrame coordinateFrame = getCoordinateFrame(nodeCenter); nodeRotation = coordinateFrame.getRotate(); break; } } } osg::Matrixd NodeTrackerManipulator::getMatrix() const { osg::Vec3d nodeCenter; osg::Quat nodeRotation; computeNodeCenterAndRotation(nodeCenter,nodeRotation); return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::rotate(nodeRotation)*osg::Matrix::translate(nodeCenter); } osg::Matrixd NodeTrackerManipulator::getInverseMatrix() const { osg::Vec3d nodeCenter; osg::Quat nodeRotation; computeNodeCenterAndRotation(nodeCenter,nodeRotation); return osg::Matrixd::translate(-nodeCenter)*osg::Matrixd::rotate(nodeRotation.inverse())*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance); } void NodeTrackerManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& center,const osg::Vec3d& up) { if (!_node) return; // compute rotation matrix osg::Vec3d lv(center-eye); _distance = lv.length(); osg::Matrixd lookat; lookat.makeLookAt(eye,center,up); _rotation = lookat.getRotate().inverse(); } // doc in parent bool NodeTrackerManipulator::performMovementLeftMouseButton( const double eventTimeDelta, const double dx, const double dy ) { osg::Vec3d nodeCenter; osg::Quat nodeRotation; computeNodeCenterAndRotation(nodeCenter, nodeRotation); // rotate camera if( getVerticalAxisFixed() ) { osg::Matrix rotation_matrix; rotation_matrix.makeRotate(_rotation); osg::Vec3d sideVector = getSideVector(rotation_matrix); osg::Vec3d localUp(0.0f,0.0f,1.0f); osg::Vec3d forwardVector = localUp^sideVector; sideVector = forwardVector^localUp; forwardVector.normalize(); sideVector.normalize(); osg::Quat rotate_elevation; rotate_elevation.makeRotate(dy,sideVector); osg::Quat rotate_azim; rotate_azim.makeRotate(-dx,localUp); _rotation = _rotation * rotate_elevation * rotate_azim; } else rotateTrackball( _ga_t0->getXnormalized(), _ga_t0->getYnormalized(), _ga_t1->getXnormalized(), _ga_t1->getYnormalized(), getThrowScale( eventTimeDelta ) ); return true; } // doc in parent bool NodeTrackerManipulator::performMovementMiddleMouseButton( const double /*eventTimeDelta*/, const double /*dx*/, const double /*dy*/ ) { osg::Vec3d nodeCenter; osg::Quat nodeRotation; computeNodeCenterAndRotation(nodeCenter, nodeRotation); return true; } // doc in parent bool NodeTrackerManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double dx, const double dy ) { osg::Vec3d nodeCenter; osg::Quat nodeRotation; computeNodeCenterAndRotation(nodeCenter, nodeRotation); return inherited::performMovementRightMouseButton(eventTimeDelta, dx, dy); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/EventQueue.cpp0000644000175000017500000004631613151044751023455 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include using namespace osgGA; EventQueue::EventQueue(GUIEventAdapter::MouseYOrientation mouseYOrientation) { _useFixedMouseInputRange = false; _startTick = osg::Timer::instance()->getStartTick(); _accumulateEventState = new GUIEventAdapter(); _accumulateEventState->setMouseYOrientation(mouseYOrientation); _firstTouchEmulatesMouse = true; } EventQueue::~EventQueue() { } void EventQueue::clear() { OpenThreads::ScopedLock lock(_eventQueueMutex); _eventQueue.clear(); } void EventQueue::setEvents(Events& events) { OpenThreads::ScopedLock lock(_eventQueueMutex); _eventQueue = events; } void EventQueue::appendEvents(Events& events) { OpenThreads::ScopedLock lock(_eventQueueMutex); _eventQueue.insert(_eventQueue.end(), events.begin(), events.end()); } void EventQueue::addEvent(Event* event) { OpenThreads::ScopedLock lock(_eventQueueMutex); _eventQueue.push_back(event); } bool EventQueue::takeEvents(Events& events) { OpenThreads::ScopedLock lock(_eventQueueMutex); if (!_eventQueue.empty()) { events.splice(events.end(), _eventQueue); return true; } else { return false; } } bool EventQueue::takeEvents(Events& events, double cutOffTime) { OpenThreads::ScopedLock lock(_eventQueueMutex); if (!_eventQueue.empty()) { // find last event if queue that came in before the cuttof. Events::reverse_iterator ritr = _eventQueue.rbegin(); for(; ritr != _eventQueue.rend() && ((*ritr)->getTime() > cutOffTime); ++ritr) {} if (ritr==_eventQueue.rend()) return false; for(Events::iterator itr = _eventQueue.begin(); itr != ritr.base(); ++itr) { events.push_back(*itr); } // make sure that the events are in ascending time order, and any out of out events // have their time reset to the next valid time after them in the events list. double previousTime = cutOffTime; for(Events::reverse_iterator itr = events.rbegin(); itr != events.rend(); ++itr) { if ((*itr)->getTime() > previousTime) { OSG_INFO<<"Reset event time from "<<(*itr)->getTime()<<" to "<setTime(previousTime); } else { previousTime = (*itr)->getTime(); } } // remove the events we are taking from the original event queue. _eventQueue.erase(_eventQueue.begin(), ritr.base()); return true; } else { return false; } } bool EventQueue::copyEvents(Events& events) const { OpenThreads::ScopedLock lock(_eventQueueMutex); if (!_eventQueue.empty()) { events.insert(events.end(),_eventQueue.begin(),_eventQueue.end()); return true; } else { return false; } } void EventQueue::syncWindowRectangleWithGraphicsContext() { const osg::GraphicsContext::Traits* traits = (getGraphicsContext()!=0) ? getGraphicsContext()->getTraits() : 0; if (traits) _accumulateEventState->setWindowRectangle(traits->x, traits->y, traits->width, traits->height, !_useFixedMouseInputRange); } osgGA::GUIEventAdapter* EventQueue::windowResize(int x, int y, int width, int height, double time) { _accumulateEventState->setWindowRectangle(x, y, width, height, !_useFixedMouseInputRange); GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::RESIZE); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::penPressure(float pressure, double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::PEN_PRESSURE); event->setPenPressure(pressure); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::penOrientation(float tiltX, float tiltY, float rotation, double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::PEN_ORIENTATION); event->setPenTiltX(tiltX); event->setPenTiltY(tiltY); event->setPenRotation(rotation); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::penProximity(GUIEventAdapter::TabletPointerType pt, bool isEntering, double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType( (isEntering) ? GUIEventAdapter::PEN_PROXIMITY_ENTER : GUIEventAdapter::PEN_PROXIMITY_LEAVE); event->setTabletPointerType(pt); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::mouseScroll(GUIEventAdapter::ScrollingMotion sm, double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::SCROLL); event->setScrollingMotion(sm); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::mouseScroll2D(float x, float y, double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::SCROLL); event->setScrollingMotionDelta(x,y); event->setTime(time); addEvent(event); return event; } void EventQueue::mouseWarped(float x, float y) { _accumulateEventState->setX(x); _accumulateEventState->setY(y); } osgGA::GUIEventAdapter* EventQueue::mouseMotion(float x, float y, double time) { _accumulateEventState->setX(x); _accumulateEventState->setY(y); GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(event->getButtonMask() ? GUIEventAdapter::DRAG : GUIEventAdapter::MOVE); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::mouseButtonPress(float x, float y, unsigned int button, double time) { _accumulateEventState->setX(x); _accumulateEventState->setY(y); switch(button) { case(1): _accumulateEventState->setButtonMask(GUIEventAdapter::LEFT_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); break; case(2): _accumulateEventState->setButtonMask(GUIEventAdapter::MIDDLE_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); break; case(3): _accumulateEventState->setButtonMask(GUIEventAdapter::RIGHT_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); break; } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::PUSH); event->setTime(time); switch(button) { case(1): event->setButton(GUIEventAdapter::LEFT_MOUSE_BUTTON); break; case(2): event->setButton(GUIEventAdapter::MIDDLE_MOUSE_BUTTON); break; case(3): event->setButton(GUIEventAdapter::RIGHT_MOUSE_BUTTON); break; } addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::mouseDoubleButtonPress(float x, float y, unsigned int button, double time) { _accumulateEventState->setX(x); _accumulateEventState->setY(y); switch(button) { case(1): _accumulateEventState->setButtonMask(GUIEventAdapter::LEFT_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); break; case(2): _accumulateEventState->setButtonMask(GUIEventAdapter::MIDDLE_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); break; case(3): _accumulateEventState->setButtonMask(GUIEventAdapter::RIGHT_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); break; } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::DOUBLECLICK); event->setTime(time); switch(button) { case(1): event->setButton(GUIEventAdapter::LEFT_MOUSE_BUTTON); break; case(2): event->setButton(GUIEventAdapter::MIDDLE_MOUSE_BUTTON); break; case(3): event->setButton(GUIEventAdapter::RIGHT_MOUSE_BUTTON); break; } addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::mouseButtonRelease(float x, float y, unsigned int button, double time) { _accumulateEventState->setX(x); _accumulateEventState->setY(y); switch(button) { case(1): _accumulateEventState->setButtonMask(~GUIEventAdapter::LEFT_MOUSE_BUTTON & _accumulateEventState->getButtonMask()); break; case(2): _accumulateEventState->setButtonMask(~GUIEventAdapter::MIDDLE_MOUSE_BUTTON & _accumulateEventState->getButtonMask()); break; case(3): _accumulateEventState->setButtonMask(~GUIEventAdapter::RIGHT_MOUSE_BUTTON & _accumulateEventState->getButtonMask()); break; } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::RELEASE); event->setTime(time); switch(button) { case(1): event->setButton(GUIEventAdapter::LEFT_MOUSE_BUTTON); break; case(2): event->setButton(GUIEventAdapter::MIDDLE_MOUSE_BUTTON); break; case(3): event->setButton(GUIEventAdapter::RIGHT_MOUSE_BUTTON); break; } addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::keyPress(int key, double time, int unmodifiedKey) { switch(key) { case(GUIEventAdapter::KEY_Shift_L): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_LEFT_SHIFT | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Shift_R): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_RIGHT_SHIFT | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Control_L): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_LEFT_CTRL | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Control_R): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_RIGHT_CTRL | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Meta_L): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_LEFT_META | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Meta_R): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_RIGHT_META | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Alt_L): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_LEFT_ALT | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Alt_R): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_RIGHT_ALT | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Super_L): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_LEFT_SUPER | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Super_R): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_RIGHT_SUPER | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Hyper_L): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_LEFT_HYPER | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Hyper_R): _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_RIGHT_HYPER | _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Caps_Lock): { if ((_accumulateEventState->getModKeyMask() & GUIEventAdapter::MODKEY_CAPS_LOCK)!=0) _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_CAPS_LOCK & _accumulateEventState->getModKeyMask()); else _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_CAPS_LOCK | _accumulateEventState->getModKeyMask()); break; } case(GUIEventAdapter::KEY_Num_Lock): { if ((_accumulateEventState->getModKeyMask() & GUIEventAdapter::MODKEY_NUM_LOCK)!=0) _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_NUM_LOCK & _accumulateEventState->getModKeyMask()); else _accumulateEventState->setModKeyMask(GUIEventAdapter::MODKEY_NUM_LOCK | _accumulateEventState->getModKeyMask()); break; } default: break; } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::KEYDOWN); event->setKey(key); event->setUnmodifiedKey(unmodifiedKey); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::keyRelease(int key, double time, int unmodifiedKey) { switch(key) { case(GUIEventAdapter::KEY_Shift_L): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_LEFT_SHIFT & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Shift_R): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_RIGHT_SHIFT & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Control_L): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_LEFT_CTRL & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Control_R): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_RIGHT_CTRL & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Meta_L): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_LEFT_META & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Meta_R): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_RIGHT_META & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Alt_L): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_LEFT_ALT & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Alt_R): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_RIGHT_ALT & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Super_L): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_LEFT_SUPER & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Super_R): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_RIGHT_SUPER & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Hyper_L): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_LEFT_HYPER & _accumulateEventState->getModKeyMask()); break; case(GUIEventAdapter::KEY_Hyper_R): _accumulateEventState->setModKeyMask(~GUIEventAdapter::MODKEY_RIGHT_HYPER & _accumulateEventState->getModKeyMask()); break; default: break; } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::KEYUP); event->setKey(key); event->setUnmodifiedKey(unmodifiedKey); event->setTime(time); addEvent(event); return event; } GUIEventAdapter* EventQueue::touchBegan(unsigned int id, GUIEventAdapter::TouchPhase phase, float x, float y, double time) { if(_firstTouchEmulatesMouse) { // emulate left mouse button press _accumulateEventState->setButtonMask(GUIEventAdapter::LEFT_MOUSE_BUTTON | _accumulateEventState->getButtonMask()); _accumulateEventState->setX(x); _accumulateEventState->setY(y); } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::PUSH); event->setTime(time); event->addTouchPoint(id, phase, x, y, 0); if(_firstTouchEmulatesMouse) event->setButton(GUIEventAdapter::LEFT_MOUSE_BUTTON); addEvent(event); return event; } GUIEventAdapter* EventQueue::touchMoved(unsigned int id, GUIEventAdapter::TouchPhase phase, float x, float y, double time) { if(_firstTouchEmulatesMouse) { _accumulateEventState->setX(x); _accumulateEventState->setY(y); } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::DRAG); event->setTime(time); event->addTouchPoint(id, phase, x, y, 0); addEvent(event); return event; } GUIEventAdapter* EventQueue::touchEnded(unsigned int id, GUIEventAdapter::TouchPhase phase, float x, float y, unsigned int tap_count, double time) { if (_firstTouchEmulatesMouse) { _accumulateEventState->setButtonMask(~GUIEventAdapter::LEFT_MOUSE_BUTTON & _accumulateEventState->getButtonMask()); _accumulateEventState->setX(x); _accumulateEventState->setY(y); } GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::RELEASE); event->setTime(time); event->addTouchPoint(id, phase, x, y, tap_count); if(_firstTouchEmulatesMouse) event->setButton(GUIEventAdapter::LEFT_MOUSE_BUTTON); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::closeWindow(double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::CLOSE_WINDOW); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::quitApplication(double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::QUIT_APPLICATION); event->setTime(time); addEvent(event); return event; } osgGA::GUIEventAdapter* EventQueue::frame(double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::FRAME); event->setTime(time); addEvent(event); return event; } GUIEventAdapter* EventQueue::createEvent() { if (_accumulateEventState.valid()) return new GUIEventAdapter(*_accumulateEventState.get()); else return new GUIEventAdapter(); } GUIEventAdapter* EventQueue::userEvent(osg::Referenced* userEventData, double time) { GUIEventAdapter* event = new GUIEventAdapter(*_accumulateEventState); event->setEventType(GUIEventAdapter::USER); event->setUserData(userEventData); event->setTime(time); addEvent(event); return event; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/TerrainManipulator.cpp0000644000175000017500000002253313151044751025202 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osg; using namespace osgGA; /// Constructor. TerrainManipulator::TerrainManipulator( int flags ) : inherited( flags ) { } /// Constructor. TerrainManipulator::TerrainManipulator( const TerrainManipulator& tm, const CopyOp& copyOp ) : osg::Callback(tm, copyOp), inherited( tm, copyOp ), _previousUp( tm._previousUp ) { } /** Sets the manipulator rotation mode. RotationMode is now deprecated by osgGA::StandardManipulator::setVerticalAxisFixed() functionality, that is used across StandardManipulator derived classes.*/ void TerrainManipulator::setRotationMode( TerrainManipulator::RotationMode mode ) { setVerticalAxisFixed( mode == ELEVATION_AZIM ); } /** Returns the manipulator rotation mode.*/ TerrainManipulator::RotationMode TerrainManipulator::getRotationMode() const { return getVerticalAxisFixed() ? ELEVATION_AZIM : ELEVATION_AZIM_ROLL; } void TerrainManipulator::setNode( Node* node ) { inherited::setNode( node ); // update model size if( _flags & UPDATE_MODEL_SIZE ) { if( _node.valid() ) { setMinimumDistance( clampBetween( _modelSize * 0.001, 0.00001, 1.0 ) ); OSG_INFO << "TerrainManipulator: setting _minimumDistance to " << _minimumDistance << std::endl; } } } void TerrainManipulator::setByMatrix(const Matrixd& matrix) { Vec3d lookVector(- matrix(2,0),-matrix(2,1),-matrix(2,2)); Vec3d eye(matrix(3,0),matrix(3,1),matrix(3,2)); OSG_INFO<<"eye point "<getBound(); float distance = (eye-bs.center()).length() + _node->getBound().radius(); Vec3d start_segment = eye; Vec3d end_segment = eye + lookVector*distance; Vec3d ip; bool hitFound = false; if (intersect(start_segment, end_segment, ip)) { OSG_INFO << "Hit terrain ok A"<< std::endl; _center = ip; _distance = (eye-ip).length(); Matrixd rotation_matrix = Matrixd::translate(0.0,0.0,-_distance)* matrix* Matrixd::translate(-_center); _rotation = rotation_matrix.getRotate(); hitFound = true; } if (!hitFound) { CoordinateFrame eyePointCoordFrame = getCoordinateFrame( eye ); if (intersect(eye+getUpVector(eyePointCoordFrame)*distance, eye-getUpVector(eyePointCoordFrame)*distance, ip)) { _center = ip; _distance = (eye-ip).length(); _rotation.set(0,0,0,1); hitFound = true; } } CoordinateFrame coordinateFrame = getCoordinateFrame(_center); _previousUp = getUpVector(coordinateFrame); clampOrientation(); } void TerrainManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up ) { if (!_node) return; // compute rotation matrix Vec3d lv(center-eye); _distance = lv.length(); _center = center; OSG_INFO << "In compute"<< std::endl; if (_node.valid()) { bool hitFound = false; double distance = lv.length(); double maxDistance = distance+2*(eye-_node->getBound().center()).length(); Vec3d farPosition = eye+lv*(maxDistance/distance); Vec3d endPoint = center; for(int i=0; !hitFound && i<2; ++i, endPoint = farPosition) { // compute the intersection with the scene. Vec3d ip; if (intersect(eye, endPoint, ip)) { _center = ip; _distance = (ip-eye).length(); hitFound = true; } } } // note LookAt = inv(CF)*inv(RM)*inv(T) which is equivalent to: // inv(R) = CF*LookAt. Matrixd rotation_matrix = Matrixd::lookAt(eye,center,up); _rotation = rotation_matrix.getRotate().inverse(); CoordinateFrame coordinateFrame = getCoordinateFrame(_center); _previousUp = getUpVector(coordinateFrame); clampOrientation(); } bool TerrainManipulator::intersect( const Vec3d& start, const Vec3d& end, Vec3d& intersection ) const { ref_ptr lsi = new osgUtil::LineSegmentIntersector(start,end); osgUtil::IntersectionVisitor iv(lsi.get()); iv.setTraversalMask(_intersectTraversalMask); _node->accept(iv); if (lsi->containsIntersections()) { intersection = lsi->getIntersections().begin()->getWorldIntersectPoint(); return true; } return false; } bool TerrainManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy ) { // pan model. double scale = -0.3f * _distance * getThrowScale( eventTimeDelta ); Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); // compute look vector. Vec3d sideVector = getSideVector(rotation_matrix); // CoordinateFrame coordinateFrame = getCoordinateFrame(_center); // Vec3d localUp = getUpVector(coordinateFrame); Vec3d localUp = _previousUp; Vec3d forwardVector =localUp^sideVector; sideVector = forwardVector^localUp; forwardVector.normalize(); sideVector.normalize(); Vec3d dv = forwardVector * (dy*scale) + sideVector * (dx*scale); _center += dv; // need to recompute the intersection point along the look vector. bool hitFound = false; if (_node.valid()) { // now reorientate the coordinate frame to the frame coords. CoordinateFrame coordinateFrame = getCoordinateFrame(_center); // need to reintersect with the terrain double distance = _node->getBound().radius()*0.25f; Vec3d ip1; Vec3d ip2; bool hit_ip1 = intersect(_center, _center + getUpVector(coordinateFrame) * distance, ip1); bool hit_ip2 = intersect(_center, _center - getUpVector(coordinateFrame) * distance, ip2); if (hit_ip1) { if (hit_ip2) { _center = (_center-ip1).length2() < (_center-ip2).length2() ? ip1 : ip2; hitFound = true; } else { _center = ip1; hitFound = true; } } else if (hit_ip2) { _center = ip2; hitFound = true; } if (!hitFound) { // ?? OSG_INFO<<"TerrainManipulator unable to intersect with terrain."< #include #include using namespace osg; using namespace osgGA; int OrbitManipulator::_minimumDistanceFlagIndex = allocateRelativeFlag(); /// Constructor. OrbitManipulator::OrbitManipulator( int flags ) : inherited( flags ), _distance( 1. ), _trackballSize( 0.8 ) { setMinimumDistance( 0.05, true ); setWheelZoomFactor( 0.1 ); if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) setAnimationTime( 0.2 ); } /// Constructor. OrbitManipulator::OrbitManipulator( const OrbitManipulator& om, const CopyOp& copyOp ) : osg::Callback(om, copyOp), inherited( om, copyOp ), _center( om._center ), _rotation( om._rotation ), _distance( om._distance ), _trackballSize( om._trackballSize ), _wheelZoomFactor( om._wheelZoomFactor ), _minimumDistance( om._minimumDistance ) { } /** Set the position of the manipulator using a 4x4 matrix.*/ void OrbitManipulator::setByMatrix( const osg::Matrixd& matrix ) { _center = osg::Vec3d( 0., 0., -_distance ) * matrix; _rotation = matrix.getRotate(); // fix current rotation if( getVerticalAxisFixed() ) fixVerticalAxis( _center, _rotation, true ); } /** Set the position of the manipulator using a 4x4 matrix.*/ void OrbitManipulator::setByInverseMatrix( const osg::Matrixd& matrix ) { setByMatrix( osg::Matrixd::inverse( matrix ) ); } /** Get the position of the manipulator as 4x4 matrix.*/ osg::Matrixd OrbitManipulator::getMatrix() const { return osg::Matrixd::translate( 0., 0., _distance ) * osg::Matrixd::rotate( _rotation ) * osg::Matrixd::translate( _center ); } /** Get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ osg::Matrixd OrbitManipulator::getInverseMatrix() const { return osg::Matrixd::translate( -_center ) * osg::Matrixd::rotate( _rotation.inverse() ) * osg::Matrixd::translate( 0.0, 0.0, -_distance ); } // doc in parent void OrbitManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ) { _center = eye + rotation * osg::Vec3d( 0., 0., -_distance ); _rotation = rotation; // fix current rotation if( getVerticalAxisFixed() ) fixVerticalAxis( _center, _rotation, true ); } // doc in parent void OrbitManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const { eye = _center - _rotation * osg::Vec3d( 0., 0., -_distance ); rotation = _rotation; } // doc in parent void OrbitManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up ) { Vec3d lv( center - eye ); Vec3d f( lv ); f.normalize(); Vec3d s( f^up ); s.normalize(); Vec3d u( s^f ); u.normalize(); osg::Matrixd rotation_matrix( s[0], u[0], -f[0], 0.0f, s[1], u[1], -f[1], 0.0f, s[2], u[2], -f[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); _center = center; _distance = lv.length(); _rotation = rotation_matrix.getRotate().inverse(); // fix current rotation if( getVerticalAxisFixed() ) fixVerticalAxis( _center, _rotation, true ); } // doc in parent void OrbitManipulator::getTransformation( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up ) const { center = _center; eye = _center + _rotation * osg::Vec3d( 0., 0., _distance ); up = _rotation * osg::Vec3d( 0., 1., 0. ); } /** Sets the transformation by heading. Heading is given as an angle in radians giving a azimuth in xy plane. Its meaning is similar to longitude used in cartography and navigation. Positive number is going to the east direction.*/ void OrbitManipulator::setHeading( double azimuth ) { CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); Vec3d localUp = getUpVector( coordinateFrame ); Vec3d localRight = getSideVector( coordinateFrame ); Vec3d dir = Quat( getElevation(), localRight ) * Quat( azimuth, localUp ) * Vec3d( 0., -_distance, 0. ); setTransformation( _center + dir, _center, localUp ); } /// Returns the heading in radians. \sa setHeading double OrbitManipulator::getHeading() const { CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); Vec3d localFront = getFrontVector( coordinateFrame ); Vec3d localRight = getSideVector( coordinateFrame ); Vec3d center, eye, tmp; getTransformation( eye, center, tmp ); Plane frontPlane( localFront, center ); double frontDist = frontPlane.distance( eye ); Plane rightPlane( localRight, center ); double rightDist = rightPlane.distance( eye ); return atan2( rightDist, -frontDist ); } /** Sets the transformation by elevation. Elevation is given as an angle in radians from xy plane. Its meaning is similar to latitude used in cartography and navigation. Positive number is going to the north direction, negative to the south.*/ void OrbitManipulator::setElevation( double elevation ) { CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); Vec3d localUp = getUpVector( coordinateFrame ); Vec3d localRight = getSideVector( coordinateFrame ); Vec3d dir = Quat( -elevation, localRight ) * Quat( getHeading(), localUp ) * Vec3d( 0., -_distance, 0. ); setTransformation( _center + dir, _center, localUp ); } /// Returns the elevation in radians. \sa setElevation double OrbitManipulator::getElevation() const { CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); Vec3d localUp = getUpVector( coordinateFrame ); localUp.normalize(); Vec3d center, eye, tmp; getTransformation( eye, center, tmp ); Plane plane( localUp, center ); double dist = plane.distance( eye ); return asin( -dist / (eye-center).length() ); } // doc in parent bool OrbitManipulator::handleMouseWheel( const GUIEventAdapter& ea, GUIActionAdapter& us ) { osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); // handle centering if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) { if( ((sm == GUIEventAdapter::SCROLL_DOWN && _wheelZoomFactor > 0.)) || ((sm == GUIEventAdapter::SCROLL_UP && _wheelZoomFactor < 0.)) ) { if( getAnimationTime() <= 0. ) { // center by mouse intersection (no animation) setCenterByMousePointerIntersection( ea, us ); } else { // start new animation only if there is no animation in progress if( !isAnimating() ) startAnimationByMousePointerIntersection( ea, us ); } } } switch( sm ) { // mouse scroll up event case GUIEventAdapter::SCROLL_UP: { // perform zoom zoomModel( _wheelZoomFactor, true ); us.requestRedraw(); us.requestContinuousUpdate( isAnimating() || _thrown ); return true; } // mouse scroll down event case GUIEventAdapter::SCROLL_DOWN: { // perform zoom zoomModel( -_wheelZoomFactor, true ); us.requestRedraw(); us.requestContinuousUpdate( isAnimating() || _thrown ); return true; } // unhandled mouse scrolling motion default: return false; } } // doc in parent bool OrbitManipulator::performMovementLeftMouseButton( const double eventTimeDelta, const double dx, const double dy ) { // rotate camera if( getVerticalAxisFixed() ) rotateWithFixedVertical( dx, dy ); else rotateTrackball( _ga_t0->getXnormalized(), _ga_t0->getYnormalized(), _ga_t1->getXnormalized(), _ga_t1->getYnormalized(), getThrowScale( eventTimeDelta ) ); return true; } // doc in parent bool OrbitManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy ) { // pan model float scale = -0.3f * _distance * getThrowScale( eventTimeDelta ); panModel( dx*scale, dy*scale ); return true; } // doc in parent bool OrbitManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double /*dx*/, const double dy ) { // zoom model zoomModel( dy * getThrowScale( eventTimeDelta ), true ); return true; } bool OrbitManipulator::performMouseDeltaMovement( const float dx, const float dy ) { // rotate camera if( getVerticalAxisFixed() ) rotateWithFixedVertical( dx, dy ); else rotateTrackball( 0.f, 0.f, dx, dy, 1.f ); return true; } void OrbitManipulator::applyAnimationStep( const double currentProgress, const double prevProgress ) { OrbitAnimationData *ad = dynamic_cast< OrbitAnimationData* >( _animationData.get() ); assert( ad ); // compute new center osg::Vec3d prevCenter, prevEye, prevUp; getTransformation( prevEye, prevCenter, prevUp ); osg::Vec3d newCenter = osg::Vec3d(prevCenter) + (ad->_movement * (currentProgress - prevProgress)); // fix vertical axis if( getVerticalAxisFixed() ) { CoordinateFrame coordinateFrame = getCoordinateFrame( newCenter ); Vec3d localUp = getUpVector( coordinateFrame ); fixVerticalAxis( newCenter - prevEye, prevUp, prevUp, localUp, false ); } // apply new transformation setTransformation( prevEye, newCenter, prevUp ); } bool OrbitManipulator::startAnimationByMousePointerIntersection( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us ) { // get current transformation osg::Vec3d prevCenter, prevEye, prevUp; getTransformation( prevEye, prevCenter, prevUp ); // center by mouse intersection if( !setCenterByMousePointerIntersection( ea, us ) ) return false; OrbitAnimationData *ad = dynamic_cast< OrbitAnimationData*>( _animationData.get() ); assert( ad ); // setup animation data and restore original transformation ad->start( osg::Vec3d(_center) - prevCenter, ea.getTime() ); setTransformation( prevEye, prevCenter, prevUp ); return true; } void OrbitManipulator::OrbitAnimationData::start( const osg::Vec3d& movement, const double startTime ) { AnimationData::start( startTime ); _movement = movement; } /** Performs trackball rotation based on two points given, for example, by mouse pointer on the screen. Scale parameter is useful, for example, when manipulator is thrown. It scales the amount of rotation based, for example, on the current frame time.*/ void OrbitManipulator::rotateTrackball( const float px0, const float py0, const float px1, const float py1, const float scale ) { osg::Vec3d axis; float angle; trackball( axis, angle, px0 + (px1-px0)*scale, py0 + (py1-py0)*scale, px0, py0 ); Quat new_rotate; new_rotate.makeRotate( angle, axis ); _rotation = _rotation * new_rotate; } /** Performs rotation horizontally by dx parameter and vertically by dy parameter, while keeping UP vector.*/ void OrbitManipulator::rotateWithFixedVertical( const float dx, const float dy ) { CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); Vec3d localUp = getUpVector( coordinateFrame ); rotateYawPitch( _rotation, dx, dy, localUp ); } /** Performs rotation horizontally by dx parameter and vertically by dy parameter, while keeping UP vector given by up parameter.*/ void OrbitManipulator::rotateWithFixedVertical( const float dx, const float dy, const Vec3f& up ) { rotateYawPitch( _rotation, dx, dy, up ); } /** Moves camera in x,y,z directions given in camera local coordinates.*/ void OrbitManipulator::panModel( const float dx, const float dy, const float dz ) { Matrix rotation_matrix; rotation_matrix.makeRotate( _rotation ); Vec3d dv( dx, dy, dz ); _center += dv * rotation_matrix; } /** Changes the distance of camera to the focal center. If pushForwardIfNeeded is true and minimumDistance is reached, the focal center is moved forward. Otherwise, distance is limited to its minimum value. \sa OrbitManipulator::setMinimumDistance */ void OrbitManipulator::zoomModel( const float dy, bool pushForwardIfNeeded ) { // scale float scale = 1.0f + dy; // minimum distance float minDist = _minimumDistance; if( getRelativeFlag( _minimumDistanceFlagIndex ) ) minDist *= _modelSize; if( _distance*scale > minDist ) { // regular zoom _distance *= scale; } else { if( pushForwardIfNeeded ) { // push the camera forward float scale = -_distance; Matrixd rotation_matrix( _rotation ); Vec3d dv = (Vec3d( 0.0f, 0.0f, -1.0f ) * rotation_matrix) * (dy * scale); _center += dv; } else { // set distance on its minimum value _distance = minDist; } } } /** * Simulate a track-ball. Project the points onto the virtual * trackball, then figure out the axis of rotation, which is the cross * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) * Note: This is a deformed trackball-- is a trackball in the center, * but is deformed into a hyperbolic sheet of rotation away from the * center. This particular function was chosen after trying out * several variations. * * It is assumed that the arguments to this routine are in the range * (-1.0 ... 1.0) */ void OrbitManipulator::trackball( osg::Vec3d& axis, float& angle, float p1x, float p1y, float p2x, float p2y ) { /* * First, figure out z-coordinates for projection of P1 and P2 to * deformed sphere */ osg::Matrixd rotation_matrix(_rotation); osg::Vec3d uv = Vec3d(0.0f,1.0f,0.0f)*rotation_matrix; osg::Vec3d sv = Vec3d(1.0f,0.0f,0.0f)*rotation_matrix; osg::Vec3d lv = Vec3d(0.0f,0.0f,-1.0f)*rotation_matrix; osg::Vec3d p1 = sv * p1x + uv * p1y - lv * tb_project_to_sphere(_trackballSize, p1x, p1y); osg::Vec3d p2 = sv * p2x + uv * p2y - lv * tb_project_to_sphere(_trackballSize, p2x, p2y); /* * Now, we want the cross product of P1 and P2 */ axis = p2^p1; axis.normalize(); /* * Figure out how much to rotate around that axis. */ float t = (p2 - p1).length() / (2.0 * _trackballSize); /* * Avoid problems with out-of-control values... */ if (t > 1.0) t = 1.0; if (t < -1.0) t = -1.0; angle = inRadians(asin(t)); } /** * Helper trackball method that projects an x,y pair onto a sphere of radius r OR * a hyperbolic sheet if we are away from the center of the sphere. */ float OrbitManipulator::tb_project_to_sphere( float r, float x, float y ) { float d, t, z; d = sqrt(x*x + y*y); /* Inside sphere */ if (d < r * 0.70710678118654752440) { z = sqrt(r*r - d*d); } /* On hyperbola */ else { t = r / 1.41421356237309504880; z = t*t / d; } return z; } /** Get the FusionDistanceMode. Used by SceneView for setting up stereo convergence.*/ osgUtil::SceneView::FusionDistanceMode OrbitManipulator::getFusionDistanceMode() const { return osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE; } /** Get the FusionDistanceValue. Used by SceneView for setting up stereo convergence.*/ float OrbitManipulator::getFusionDistanceValue() const { return _distance; } /** Set the center of the manipulator. */ void OrbitManipulator::setCenter( const Vec3d& center ) { _center = center; } /** Get the center of the manipulator. */ const Vec3d& OrbitManipulator::getCenter() const { return _center; } /** Set the rotation of the manipulator. */ void OrbitManipulator::setRotation( const Quat& rotation ) { _rotation = rotation; } /** Get the rotation of the manipulator. */ const Quat& OrbitManipulator::getRotation() const { return _rotation; } /** Set the distance of camera to the center. */ void OrbitManipulator::setDistance( double distance ) { _distance = distance; } /** Get the distance of the camera to the center. */ double OrbitManipulator::getDistance() const { return _distance; } /** Set the size of the trackball. Value is relative to the model size. */ void OrbitManipulator::setTrackballSize( const double& size ) { /* * This size should really be based on the distance from the center of * rotation to the point on the object underneath the mouse. That * point would then track the mouse as closely as possible. This is a * simple example, though, so that is left as an Exercise for the * Programmer. */ _trackballSize = size; clampBetweenRange( _trackballSize, 0.1, 1.0, "TrackballManipulator::setTrackballSize(float)" ); } /** Set the mouse wheel zoom factor. The amount of camera movement on each mouse wheel event is computed as the current distance to the center multiplied by this factor. For example, value of 0.1 will short distance to center by 10% on each wheel up event. Use negative value for reverse mouse wheel direction.*/ void OrbitManipulator::setWheelZoomFactor( double wheelZoomFactor ) { _wheelZoomFactor = wheelZoomFactor; } /** Set the minimum distance of the eye point from the center before the center is pushed forward.*/ void OrbitManipulator::setMinimumDistance( const double& minimumDistance, bool relativeToModelSize ) { _minimumDistance = minimumDistance; setRelativeFlag( _minimumDistanceFlagIndex, relativeToModelSize ); } /** Get the minimum distance of the eye point from the center before the center is pushed forward.*/ double OrbitManipulator::getMinimumDistance( bool *relativeToModelSize ) const { if( relativeToModelSize ) *relativeToModelSize = getRelativeFlag( _minimumDistanceFlagIndex ); return _minimumDistance; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/DriveManipulator.cpp0000644000175000017500000003614113151044751024647 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #if defined(_MSC_VER) #pragma warning( disable : 4786 ) #endif #include #include #include #include using namespace osg; using namespace osgGA; #define DRIVER_HEIGHT 15 // #define ABOSULTE_PITCH 1 // #define INCREMENTAL_PITCH 1 #define KEYBOARD_PITCH 1 static double getHeightOfDriver() { double height = 1.5; if (getenv("OSG_DRIVE_MANIPULATOR_HEIGHT")) { height = osg::asciiToDouble(getenv("OSG_DRIVE_MANIPULATOR_HEIGHT")); } OSG_INFO<<"DriveManipulator::_height set to =="<getBound(); _modelScale = boundingSphere._radius; //_height = sqrtf(_modelScale)*0.03; //_buffer = sqrtf(_modelScale)*0.05; _height = getHeightOfDriver(); _buffer = _height*2.5; } if (getAutoComputeHomePosition()) computeHomePosition(); } const osg::Node* DriveManipulator::getNode() const { return _node.get(); } osg::Node* DriveManipulator::getNode() { return _node.get(); } bool DriveManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const { osg::ref_ptr lsi = new osgUtil::LineSegmentIntersector(start,end); osgUtil::IntersectionVisitor iv(lsi.get()); iv.setTraversalMask(_intersectTraversalMask); _node->accept(iv); if (lsi->containsIntersections()) { intersection = lsi->getIntersections().begin()->getWorldIntersectPoint(); normal = lsi->getIntersections().begin()->getWorldIntersectNormal(); return true; } return false; } void DriveManipulator::computeHomePosition() { if(_node.get()) { const osg::BoundingSphere& boundingSphere=_node->getBound(); osg::Vec3d ep = boundingSphere._center; osg::Vec3d bp = ep; osg::CoordinateFrame cf=getCoordinateFrame(ep); ep -= getUpVector(cf)* _modelScale*0.0001; bp -= getUpVector(cf)* _modelScale; // check to see if any obstruction in front. bool positionSet = false; osg::Vec3d ip, np; if (intersect(ep, bp, ip, np)) { osg::Vec3d uv; if (np * getUpVector(cf)>0.0) uv = np; else uv = -np; ep = ip; ep += getUpVector(cf)*_height; osg::Vec3d lv = uv^osg::Vec3d(1.0,0.0,0.0); setHomePosition(ep,ep+lv,uv); positionSet = true; } if (!positionSet) { bp = ep; bp += getUpVector(cf)*_modelScale; if (intersect(ep, bp, ip, np)) { osg::Vec3d uv; if (np*getUpVector(cf)>0.0) uv = np; else uv = -np; ep = ip; ep += getUpVector(cf)*_height; osg::Vec3d lv = uv^osg::Vec3d(1.0,0.0,0.0); setHomePosition(ep,ep+lv,uv); positionSet = true; } } if (!positionSet) { setHomePosition( boundingSphere._center+osg::Vec3d( 0.0,-2.0 * boundingSphere._radius,0.0), boundingSphere._center+osg::Vec3d( 0.0,-2.0 * boundingSphere._radius,0.0)+osg::Vec3d(0.0,1.0,0.0), osg::Vec3d(0.0,0.0,1.0)); } } } void DriveManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us) { if (getAutoComputeHomePosition()) computeHomePosition(); computePosition(_homeEye, _homeCenter, _homeUp); _velocity = 0.0; _pitch = 0.0; us.requestRedraw(); us.requestContinuousUpdate(false); us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2.0f,(ea.getYmin()+ea.getYmax())/2.0f); flushMouseEventStack(); } void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us) { flushMouseEventStack(); us.requestContinuousUpdate(false); _velocity = 0.0; osg::Vec3d ep = _eye; osg::CoordinateFrame cf=getCoordinateFrame(ep); Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); osg::Vec3d sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix; osg::Vec3d bp = ep; bp -= getUpVector(cf)*_modelScale; bool positionSet = false; osg::Vec3d ip, np; if (intersect(ep, bp, ip, np)) { osg::Vec3d uv; if (np*getUpVector(cf)>0.0) uv = np; else uv = -np; ep = ip+uv*_height; osg::Vec3d lv = uv^sv; computePosition(ep,ep+lv,uv); positionSet = true; } if (!positionSet) { bp = ep; bp += getUpVector(cf)*_modelScale; if (intersect(ep, bp, ip, np)) { osg::Vec3d uv; if (np*getUpVector(cf)>0.0f) uv = np; else uv = -np; ep = ip+uv*_height; osg::Vec3d lv = uv^sv; computePosition(ep,ep+lv,uv); positionSet = true; } } if (ea.getEventType()!=GUIEventAdapter::RESIZE) { us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2.0f,(ea.getYmin()+ea.getYmax())/2.0f); } } bool DriveManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) { switch(ea.getEventType()) { case(GUIEventAdapter::FRAME): addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); return false; case(GUIEventAdapter::RESIZE): init(ea,us); us.requestRedraw(); return true; default: break; } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(GUIEventAdapter::PUSH): { addMouseEvent(ea); us.requestContinuousUpdate(true); if (calcMovement()) us.requestRedraw(); return true; } case(GUIEventAdapter::RELEASE): { addMouseEvent(ea); us.requestContinuousUpdate(true); if (calcMovement()) us.requestRedraw(); return true; } case(GUIEventAdapter::DRAG): { addMouseEvent(ea); us.requestContinuousUpdate(true); if (calcMovement()) us.requestRedraw(); return true; } case(GUIEventAdapter::MOVE): { addMouseEvent(ea); us.requestContinuousUpdate(true); if (calcMovement()) us.requestRedraw(); return true; } case(GUIEventAdapter::KEYDOWN): { if (ea.getKey()==GUIEventAdapter::KEY_Space) { flushMouseEventStack(); home(ea,us); return true; } else if (ea.getKey()=='q') { _speedMode = USE_MOUSE_Y_FOR_SPEED; return true; } else if (ea.getKey()=='a') { _speedMode = USE_MOUSE_BUTTONS_FOR_SPEED; return true; } #ifdef KEYBOARD_PITCH else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Up || ea.getKey()=='9') { _pitchUpKeyPressed = true; return true; } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Down || ea.getKey()=='6') { _pitchDownKeyPressed = true; return true; } #endif return false; } case(GUIEventAdapter::KEYUP): { #ifdef KEYBOARD_PITCH if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Up || ea.getKey()=='9') { _pitchUpKeyPressed = false; return true; } else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Down || ea.getKey()=='6') { _pitchDownKeyPressed = false; return true; } #endif return false; } default: return false; } } void DriveManipulator::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding("Drive: Space","Reset the viewing position to home"); usage.addKeyboardMouseBinding("Drive: q","Use mouse y for controlling speed"); usage.addKeyboardMouseBinding("Drive: a","Use mouse middle,right mouse buttons for speed"); usage.addKeyboardMouseBinding("Drive: Down","Cursor down key to look downwards"); usage.addKeyboardMouseBinding("Drive: Up","Cursor up key to look upwards"); } void DriveManipulator::flushMouseEventStack() { _ga_t1 = NULL; _ga_t0 = NULL; } void DriveManipulator::addMouseEvent(const GUIEventAdapter& ea) { _ga_t1 = _ga_t0; _ga_t0 = &ea; } void DriveManipulator::setByMatrix(const osg::Matrixd& matrix) { _eye = matrix.getTrans(); _rotation = matrix.getRotate(); } osg::Matrixd DriveManipulator::getMatrix() const { return osg::Matrixd::rotate(_pitch,1.0,0.0,0.0)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_eye); } osg::Matrixd DriveManipulator::getInverseMatrix() const { return osg::Matrixd::translate(-_eye)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::rotate(-_pitch,1.0,0.0,0.0); } void DriveManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& center,const osg::Vec3d& up) { osg::Vec3d lv = center-eye; osg::Vec3d f(lv); f.normalize(); osg::Vec3d s(f^up); s.normalize(); osg::Vec3d u(s^f); u.normalize(); osg::Matrixd rotation_matrix(s[0], u[0], -f[0], 0.0, s[1], u[1], -f[1], 0.0, s[2], u[2], -f[2], 0.0, 0.0, 0.0, 0.0, 1.0); _eye = eye; _rotation = rotation_matrix.getRotate().inverse(); } bool DriveManipulator::calcMovement() { // return if less then two events have been added. if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; double dt = _ga_t0->getTime()-_ga_t1->getTime(); if (dt<0.0f) { OSG_INFO << "warning dt = "<getYnormalized(); _velocity = _height*dy; break; } case(USE_MOUSE_BUTTONS_FOR_SPEED): { unsigned int buttonMask = _ga_t1->getButtonMask(); if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) { // pan model. _velocity += dt*accelerationFactor; } else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) { _velocity = 0.0; } else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) { _velocity -= dt*accelerationFactor; } break; } } osg::CoordinateFrame cf=getCoordinateFrame(_eye); osg::Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); osg::Vec3d up = osg::Vec3d(0.0,1.0,0.0) * rotation_matrix; osg::Vec3d lv = osg::Vec3d(0.0,0.0,-1.0) * rotation_matrix; osg::Vec3d sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix; // rotate the camera. double dx = _ga_t0->getXnormalized(); double yaw = -inDegrees(dx*50.0*dt); #ifdef KEYBOARD_PITCH double pitch_delta = 0.5; if (_pitchUpKeyPressed) _pitch += pitch_delta*dt; if (_pitchDownKeyPressed) _pitch -= pitch_delta*dt; #endif #if defined(ABOSULTE_PITCH) // absolute pitch double dy = _ga_t0->getYnormalized(); _pitch = -dy*0.5; #elif defined(INCREMENTAL_PITCH) // incremental pitch double dy = _ga_t0->getYnormalized(); _pitch += dy*dt; #endif osg::Quat yaw_rotation; yaw_rotation.makeRotate(yaw,up); _rotation *= yaw_rotation; rotation_matrix.makeRotate(_rotation); sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix; // movement is big enough the move the eye point along the look vector. if (fabs(_velocity*dt)>1e-8) { double distanceToMove = _velocity*dt; double signedBuffer; if (distanceToMove>=0.0) signedBuffer=_buffer; else signedBuffer=-_buffer; // check to see if any obstruction in front. osg::Vec3d ip, np; if (intersect(_eye,_eye+lv*(signedBuffer+distanceToMove), ip, np)) { if (distanceToMove>=0.0) { distanceToMove = (ip-_eye).length()-_buffer; } else { distanceToMove = _buffer-(ip-_eye).length(); } _velocity = 0.0; } // check to see if forward point is correct height above terrain. osg::Vec3d fp = _eye + lv*distanceToMove; osg::Vec3d lfp = fp - up*(_height*5.0); if (intersect(fp, lfp, ip, np)) { if (up*np>0.0) up = np; else up = -np; _eye = ip+up*_height; lv = up^sv; computePosition(_eye,_eye+lv,up); return true; } // no hit on the terrain found therefore resort to a fall under // under the influence of gravity. osg::Vec3d dp = lfp; dp -= getUpVector(cf)* (2.0*_modelScale); if (intersect(lfp, dp, ip, np)) { if (up*np>0.0) up = np; else up = -np; _eye = ip+up*_height; lv = up^sv; computePosition(_eye,_eye+lv,up); return true; } // no collision with terrain has been found therefore track horizontally. lv *= (_velocity*dt); _eye += lv; } return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/FlightManipulator.cpp0000644000175000017500000001402113151044751025004 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include using namespace osg; using namespace osgGA; /// Constructor. FlightManipulator::FlightManipulator( int flags ) : inherited( flags ), _yawMode( YAW_AUTOMATICALLY_WHEN_BANKED ) { } /// Constructor. FlightManipulator::FlightManipulator( const FlightManipulator& fm, const CopyOp& copyOp ) : osg::Callback(fm, copyOp), inherited( fm, copyOp ), _yawMode( fm._yawMode ) { } void FlightManipulator::init( const GUIEventAdapter& ea, GUIActionAdapter& us ) { inherited::init( ea, us ); // center mouse pointer centerMousePointer( ea, us ); } void FlightManipulator::home( const GUIEventAdapter& ea, GUIActionAdapter& us ) { inherited::home( ea, us ); // center mouse pointer centerMousePointer( ea, us ); } // doc in parent bool FlightManipulator::handleFrame( const GUIEventAdapter& ea, GUIActionAdapter& us ) { addMouseEvent( ea ); if( performMovement() ) us.requestRedraw(); return false; } // doc in parent bool FlightManipulator::handleMouseMove( const GUIEventAdapter& ea, GUIActionAdapter& us ) { return flightHandleEvent( ea, us ); } // doc in parent bool FlightManipulator::handleMouseDrag( const GUIEventAdapter& ea, GUIActionAdapter& us ) { return flightHandleEvent( ea, us ); } // doc in parent bool FlightManipulator::handleMousePush( const GUIEventAdapter& ea, GUIActionAdapter& us ) { return flightHandleEvent( ea, us ); } // doc in parent bool FlightManipulator::handleMouseRelease( const GUIEventAdapter& ea, GUIActionAdapter& us ) { return flightHandleEvent( ea, us ); } bool FlightManipulator::handleKeyDown( const GUIEventAdapter& ea, GUIActionAdapter& us ) { if( inherited::handleKeyDown( ea, us ) ) return true; if( ea.getKey() == 'q' ) { _yawMode = YAW_AUTOMATICALLY_WHEN_BANKED; return true; } else if (ea.getKey()=='a') { _yawMode = NO_AUTOMATIC_YAW; return true; } return false; } /// General flight-style event handler bool FlightManipulator::flightHandleEvent( const GUIEventAdapter& ea, GUIActionAdapter& us ) { addMouseEvent( ea ); us.requestContinuousUpdate( true ); if( performMovement() ) us.requestRedraw(); return true; } void FlightManipulator::getUsage( ApplicationUsage& usage ) const { inherited::getUsage( usage ); usage.addKeyboardMouseBinding( getManipulatorName() + ": q", "Automatically yaw when banked (default)" ); usage.addKeyboardMouseBinding( getManipulatorName() + ": a", "No yaw when banked" ); } /** Configure the Yaw control for the flight model. */ void FlightManipulator::setYawControlMode( YawControlMode ycm ) { _yawMode = ycm; } bool FlightManipulator::performMovement() { // return if less then two events have been added. if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; double eventTimeDelta = _ga_t0->getTime()-_ga_t1->getTime(); if (eventTimeDelta<0.0f) { OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl; eventTimeDelta = 0.0f; } unsigned int buttonMask = _ga_t1->getButtonMask(); if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) { performMovementLeftMouseButton(eventTimeDelta, 0., 0.); } else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) { performMovementMiddleMouseButton(eventTimeDelta, 0., 0.); } else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) { performMovementRightMouseButton(eventTimeDelta, 0., 0.); } float dx = _ga_t0->getXnormalized(); float dy = _ga_t0->getYnormalized(); CoordinateFrame cf=getCoordinateFrame(_eye); Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); Vec3d up = Vec3d(0.0,1.0,0.0) * rotation_matrix; Vec3d lv = Vec3d(0.0,0.0,-1.0) * rotation_matrix; Vec3d sv = lv^up; sv.normalize(); double pitch = -inDegrees(dy*50.0f*eventTimeDelta); double roll = inDegrees(dx*50.0f*eventTimeDelta); Quat delta_rotate; Quat roll_rotate; Quat pitch_rotate; pitch_rotate.makeRotate(pitch,sv.x(),sv.y(),sv.z()); roll_rotate.makeRotate(roll,lv.x(),lv.y(),lv.z()); delta_rotate = pitch_rotate*roll_rotate; if (_yawMode==YAW_AUTOMATICALLY_WHEN_BANKED) { //float bank = asinf(sv.z()); double bank = asinf(sv *getUpVector(cf)); double yaw = inRadians(bank)*eventTimeDelta; Quat yaw_rotate; //yaw_rotate.makeRotate(yaw,0.0f,0.0f,1.0f); yaw_rotate.makeRotate(yaw,getUpVector(cf)); delta_rotate = delta_rotate*yaw_rotate; } lv *= (_velocity*eventTimeDelta); _eye += lv; _rotation = _rotation*delta_rotate; return true; } bool FlightManipulator::performMovementLeftMouseButton( const double eventTimeDelta, const double /*dx*/, const double /*dy*/ ) { // pan model _velocity += eventTimeDelta * (_acceleration + _velocity); return true; } bool FlightManipulator::performMovementMiddleMouseButton( const double /*eventTimeDelta*/, const double /*dx*/, const double /*dy*/ ) { _velocity = 0.0f; return true; } bool FlightManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double /*dx*/, const double /*dy*/ ) { _velocity -= eventTimeDelta * (_acceleration + _velocity); return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/FirstPersonManipulator.cpp0000644000175000017500000002566413151044751026064 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. * * FirstPersonManipulator code Copyright (C) 2010 PCJohn (Jan Peciva) * while some pieces of code were taken from OSG. * Thanks to company Cadwork (www.cadwork.ch) and * Brno University of Technology (www.fit.vutbr.cz) for open-sourcing this work. */ #include #include using namespace osg; using namespace osgGA; int FirstPersonManipulator::_accelerationFlagIndex = allocateRelativeFlag(); int FirstPersonManipulator::_maxVelocityFlagIndex = allocateRelativeFlag(); int FirstPersonManipulator::_wheelMovementFlagIndex = allocateRelativeFlag(); /// Constructor. FirstPersonManipulator::FirstPersonManipulator( int flags ) : inherited( flags ), _velocity( 0. ) { setAcceleration( 1.0, true ); setMaxVelocity( 0.25, true ); setWheelMovement( 0.05, true ); if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) setAnimationTime( 0.2 ); } /// Constructor. FirstPersonManipulator::FirstPersonManipulator( const FirstPersonManipulator& fpm, const CopyOp& copyOp ) : osg::Callback(fpm, copyOp), inherited( fpm, copyOp ), _eye( fpm._eye ), _rotation( fpm._rotation ), _velocity( fpm._velocity ), _acceleration( fpm._acceleration ), _maxVelocity( fpm._maxVelocity ), _wheelMovement( fpm._wheelMovement ) { } /** Set the position of the manipulator using a 4x4 matrix.*/ void FirstPersonManipulator::setByMatrix( const Matrixd& matrix ) { // set variables _eye = matrix.getTrans(); _rotation = matrix.getRotate(); // fix current rotation if( getVerticalAxisFixed() ) fixVerticalAxis( _eye, _rotation, true ); } /** Set the position of the manipulator using a 4x4 matrix.*/ void FirstPersonManipulator::setByInverseMatrix( const Matrixd& matrix ) { setByMatrix( Matrixd::inverse( matrix ) ); } /** Get the position of the manipulator as 4x4 matrix.*/ Matrixd FirstPersonManipulator::getMatrix() const { return Matrixd::rotate( _rotation ) * Matrixd::translate( _eye ); } /** Get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ Matrixd FirstPersonManipulator::getInverseMatrix() const { return Matrixd::translate( -_eye ) * Matrixd::rotate( _rotation.inverse() ); } // doc in parent void FirstPersonManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ) { // set variables _eye = eye; _rotation = rotation; // fix current rotation if( getVerticalAxisFixed() ) fixVerticalAxis( _eye, _rotation, true ); } // doc in parent void FirstPersonManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const { eye = _eye; rotation = _rotation; } // doc in parent void FirstPersonManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up ) { // set variables osg::Matrixd m( osg::Matrixd::lookAt( eye, center, up ) ); _eye = eye; _rotation = m.getRotate().inverse(); // fix current rotation if( getVerticalAxisFixed() ) fixVerticalAxis( _eye, _rotation, true ); } // doc in parent void FirstPersonManipulator::getTransformation( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up ) const { center = _eye + _rotation * osg::Vec3d( 0.,0.,-1. ); eye = _eye; up = _rotation * osg::Vec3d( 0.,1.,0. ); } /** Sets velocity. * * There are no checks for maximum velocity applied. */ void FirstPersonManipulator::setVelocity( const double& velocity ) { _velocity = velocity; } /** Sets acceleration. * * If acceleration effect is unwanted, it can be set to DBL_MAX. * Then, there will be no acceleration and object will reach its * maximum velocity immediately. */ void FirstPersonManipulator::setAcceleration( const double& acceleration, bool relativeToModelSize ) { _acceleration = acceleration; setRelativeFlag( _accelerationFlagIndex, relativeToModelSize ); } /// Returns acceleration speed. double FirstPersonManipulator::getAcceleration( bool *relativeToModelSize ) const { if( relativeToModelSize ) *relativeToModelSize = getRelativeFlag( _accelerationFlagIndex ); return _acceleration; } /** Sets maximum velocity. * * If acceleration is set to DBL_MAX, there is no speeding up. * Instead, maximum velocity is used for velocity at once without acceleration. */ void FirstPersonManipulator::setMaxVelocity( const double& maxVelocity, bool relativeToModelSize ) { _maxVelocity = maxVelocity; setRelativeFlag( _maxVelocityFlagIndex, relativeToModelSize ); } /// Returns maximum velocity. double FirstPersonManipulator::getMaxVelocity( bool *relativeToModelSize ) const { if( relativeToModelSize ) *relativeToModelSize = getRelativeFlag( _maxVelocityFlagIndex ); return _maxVelocity; } /// Sets movement size on single wheel step. void FirstPersonManipulator::setWheelMovement( const double& wheelMovement, bool relativeToModelSize ) { _wheelMovement = wheelMovement; setRelativeFlag( _wheelMovementFlagIndex, relativeToModelSize ); } /// Returns movement size on single wheel step. double FirstPersonManipulator::getWheelMovement( bool *relativeToModelSize ) const { if( relativeToModelSize ) *relativeToModelSize = getRelativeFlag( _wheelMovementFlagIndex ); return _wheelMovement; } void FirstPersonManipulator::home( double currentTime ) { inherited::home( currentTime ); _velocity = 0.; } void FirstPersonManipulator::home( const GUIEventAdapter& ea, GUIActionAdapter& us ) { inherited::home( ea, us ); _velocity = 0.; } void FirstPersonManipulator::init( const GUIEventAdapter& ea, GUIActionAdapter& us ) { inherited::init( ea, us ); // stop movement _velocity = 0.; } // doc in parent bool FirstPersonManipulator::handleMouseWheel( const GUIEventAdapter& ea, GUIActionAdapter& us ) { osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); // handle centering if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) { if( ((sm == GUIEventAdapter::SCROLL_DOWN) && (_wheelMovement > 0.)) || ((sm == GUIEventAdapter::SCROLL_UP) && (_wheelMovement < 0.)) ) { // stop thrown animation _thrown = false; if( getAnimationTime() <= 0. ) // center by mouse intersection (no animation) setCenterByMousePointerIntersection( ea, us ); else { // start new animation only if there is no animation in progress if( !isAnimating() ) startAnimationByMousePointerIntersection( ea, us ); } } } switch( sm ) { // mouse scroll up event case GUIEventAdapter::SCROLL_UP: { // move forward moveForward( isAnimating() ? dynamic_cast< FirstPersonAnimationData* >( _animationData.get() )->_targetRot : _rotation, -_wheelMovement * (getRelativeFlag( _wheelMovementFlagIndex ) ? _modelSize : 1. )); us.requestRedraw(); us.requestContinuousUpdate( isAnimating() || _thrown ); return true; } // mouse scroll down event case GUIEventAdapter::SCROLL_DOWN: { // move backward moveForward( _wheelMovement * (getRelativeFlag( _wheelMovementFlagIndex ) ? _modelSize : 1. )); _thrown = false; us.requestRedraw(); us.requestContinuousUpdate( isAnimating() || _thrown ); return true; } // unhandled mouse scrolling motion default: return false; } } // doc in parent bool FirstPersonManipulator::performMovementLeftMouseButton( const double /*eventTimeDelta*/, const double dx, const double dy ) { // world up vector CoordinateFrame coordinateFrame = getCoordinateFrame( _eye ); Vec3d localUp = getUpVector( coordinateFrame ); rotateYawPitch( _rotation, dx, dy, localUp ); return true; } bool FirstPersonManipulator::performMouseDeltaMovement( const float dx, const float dy ) { // rotate camera if( getVerticalAxisFixed() ) { // world up vector CoordinateFrame coordinateFrame = getCoordinateFrame( _eye ); Vec3d localUp = getUpVector( coordinateFrame ); rotateYawPitch( _rotation, dx, dy, localUp ); } else rotateYawPitch( _rotation, dx, dy ); return true; } /// Move camera forward by distance parameter. void FirstPersonManipulator::moveForward( const double distance ) { moveForward( _rotation, distance ); } /// Move camera forward by distance parameter. void FirstPersonManipulator::moveForward( const Quat& rotation, const double distance ) { _eye += rotation * Vec3d( 0., 0., -distance ); } /// Move camera right by distance parameter. void FirstPersonManipulator::moveRight( const double distance ) { _eye += _rotation * Vec3d( distance, 0., 0. ); } /// Move camera up by distance parameter. void FirstPersonManipulator::moveUp( const double distance ) { _eye += _rotation * Vec3d( 0., distance, 0. ); } void FirstPersonManipulator::applyAnimationStep( const double currentProgress, const double /*prevProgress*/ ) { FirstPersonAnimationData *ad = dynamic_cast< FirstPersonAnimationData* >( _animationData.get() ); assert( ad ); // compute new rotation _rotation.slerp( currentProgress, ad->_startRot, ad->_targetRot ); // fix vertical axis if( getVerticalAxisFixed() ) fixVerticalAxis( _eye, _rotation, false ); } // doc in parent bool FirstPersonManipulator::startAnimationByMousePointerIntersection( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us ) { // get current transformation osg::Vec3d prevEye; osg::Quat prevRot; getTransformation( prevEye, prevRot ); // center by mouse intersection if( !setCenterByMousePointerIntersection( ea, us ) ) return false; FirstPersonAnimationData *ad = dynamic_cast< FirstPersonAnimationData*>( _animationData.get() ); assert( ad ); // setup animation data and restore original transformation ad->start( prevRot, _rotation, ea.getTime() ); setTransformation( _eye, prevRot ); return true; } void FirstPersonManipulator::FirstPersonAnimationData::start( const Quat& startRotation, const Quat& targetRotation, const double startTime ) { AnimationData::start( startTime ); _startRot = startRotation; _targetRot = targetRotation; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/CameraManipulator.cpp0000644000175000017500000001007413151044751024763 0ustar albertoalberto#include #include #include #include #include #include using namespace osg; using namespace osgGA; CameraManipulator::CameraManipulator() { _intersectTraversalMask = 0xffffffff; _autoComputeHomePosition = true; _homeEye.set(0.0,-1.0,0.0); _homeCenter.set(0.0,0.0,0.0); _homeUp.set(0.0,0.0,1.0); } CameraManipulator::CameraManipulator(const CameraManipulator& mm, const CopyOp& copyOp) : osg::Callback(mm, copyOp), inherited(mm, copyOp), _intersectTraversalMask(mm._intersectTraversalMask), _autoComputeHomePosition(mm._autoComputeHomePosition), _homeEye(mm._homeEye), _homeCenter(mm._homeCenter), _homeUp(mm._homeUp), _coordinateFrameCallback(dynamic_cast(copyOp(mm._coordinateFrameCallback.get()))) { } CameraManipulator::~CameraManipulator() { } std::string CameraManipulator::getManipulatorName() const { const char* className = this->className(); const char* manipString = strstr(className, "Manipulator"); if (!manipString) return std::string(className); else return std::string(className, manipString-className); } bool CameraManipulator::handle(const GUIEventAdapter&,GUIActionAdapter&) { return false; } /** Compute the home position. * * The computation considers camera's fov (field of view) and model size and * positions camera far enough to fit the model to the screen. * * camera parameter enables computations of camera's fov. If camera is NULL, * scene to camera distance can not be computed and default value is used, * based on model size only. * * useBoundingBox parameter enables to use bounding box instead of bounding sphere * for scene bounds. Bounding box provide more precise scene center that may be * important for many applications.*/ void CameraManipulator::computeHomePosition(const osg::Camera *camera, bool useBoundingBox) { if (getNode()) { osg::BoundingSphere boundingSphere; OSG_INFO<<" CameraManipulator::computeHomePosition("<accept(cbVisitor); osg::BoundingBox &bb = cbVisitor.getBoundingBox(); if (bb.valid()) boundingSphere.expandBy(bb); else boundingSphere = getNode()->getBound(); } else { // compute bounding sphere boundingSphere = getNode()->getBound(); } OSG_INFO<<" boundingSphere.center() = ("< 0.02) zoomModel( relativeChange , true ); // drag gesture const osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f; const float scale = -0.3f * _distance * getThrowScale( eventTimeDelta ); //osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl; panModel( delta.x() * scale, delta.y() * scale); } bool MultiTouchTrackballManipulator::handle( const GUIEventAdapter& ea, GUIActionAdapter& us ) { bool handled(false); switch(ea.getEventType()) { case osgGA::GUIEventAdapter::PUSH: case osgGA::GUIEventAdapter::DRAG: case osgGA::GUIEventAdapter::RELEASE: if (ea.isMultiTouchEvent()) { double eventTimeDelta = 1/60.0; //_ga_t0->getTime() - _ga_t1->getTime(); if( eventTimeDelta < 0. ) { OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl; eventTimeDelta = 0.; } osgGA::GUIEventAdapter::TouchData* data = ea.getTouchData(); // three touches or two taps for home position if ((data->getNumTouchPoints() == 3) || ((data->getNumTouchPoints() == 1) && (data->get(0).tapCount >= 2))) { flushMouseEventStack(); _thrown = false; home(ea,us); handled = true; } else if (data->getNumTouchPoints() >= 2) { if ((_lastEvent.valid()) && (_lastEvent->getTouchData()->getNumTouchPoints() >= 2)) { handleMultiTouchDrag(&ea, _lastEvent.get(), eventTimeDelta); } handled = true; } _lastEvent = new GUIEventAdapter(ea); // check if all touches ended unsigned int num_touches_ended(0); for(osgGA::GUIEventAdapter::TouchData::iterator i = data->begin(); i != data->end(); ++i) { if ((*i).phase == osgGA::GUIEventAdapter::TOUCH_ENDED) num_touches_ended++; } if(num_touches_ended == data->getNumTouchPoints()) { _lastEvent = NULL; } } break; default: break; } return handled ? handled : TrackballManipulator::handle(ea, us); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/SphericalManipulator.cpp0000644000175000017500000003157013151044751025511 0ustar albertoalberto #include #include #include #include using namespace osg; using namespace osgGA; //-------------------------------------------------------------------------------------------------- SphericalManipulator::SphericalManipulator() { _modelScale = 0.01; _minimumZoomScale = 0.1; _thrown = false; _allowThrow = true; _distance=1.0; _homeDistance=1.0; _zoomDelta = 0.1; _heading=0.0; _elevation=osg::PI_2; _rotationMode = ELEVATION_HEADING; } //-------------------------------------------------------------------------------------------------- SphericalManipulator::~SphericalManipulator() { } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::setNode(osg::Node* node) { _node = node; if (_node.get()) { const osg::BoundingSphere& boundingSphere=_node->getBound(); _modelScale = boundingSphere._radius; } if (getAutoComputeHomePosition()) computeHomePosition(); } //-------------------------------------------------------------------------------------------------- const osg::Node* SphericalManipulator::getNode() const { return _node.get(); } //-------------------------------------------------------------------------------------------------- osg::Node* SphericalManipulator::getNode() { return _node.get(); } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::setRotationMode(RotationMode mode) { if(_rotationMode == mode) return; _rotationMode=mode; if(_rotationMode == MAP) _elevation=PI_2; } //-------------------------------------------------------------------------------------------------- bool SphericalManipulator::setDistance(double distance) { if(distance <= 0) return false; _distance=distance; return true; } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::home(double /*currentTime*/) { if(getAutoComputeHomePosition()) computeHomePosition(); _heading=3*PI_2; _elevation=0.0; _center=_homeCenter; _distance=_homeDistance; _thrown = false; } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::home(const GUIEventAdapter& ea ,GUIActionAdapter& us) { home(ea.getTime()); us.requestRedraw(); us.requestContinuousUpdate(false); } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& ) { flushMouseEventStack(); } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding("Spherical: Space","Reset the viewing position to home"); usage.addKeyboardMouseBinding("Spherical: SHIFT","Rotates vertically only"); usage.addKeyboardMouseBinding("Spherical: ALT","Rotates horizontally only"); } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::zoomOn(const osg::BoundingSphere& bound) { computeViewPosition(bound,_modelScale,_distance,_center); _thrown = false; } //-------------------------------------------------------------------------------------------------- bool SphericalManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) { switch(ea.getEventType()) { case(GUIEventAdapter::FRAME): { double current_frame_time = ea.getTime(); _delta_frame_time = current_frame_time - _last_frame_time; _last_frame_time = current_frame_time; if (_thrown) { if (calcMovement()) us.requestRedraw(); } return false; } default: break; } if (ea.getHandled()) return false; switch(ea.getEventType()) { case(GUIEventAdapter::PUSH): { flushMouseEventStack(); addMouseEvent(ea); us.requestContinuousUpdate(false); _thrown = false; return true; } case(GUIEventAdapter::RELEASE): { if (ea.getButtonMask()==0) { double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX; if (timeSinceLastRecordEvent>0.02) flushMouseEventStack(); if (isMouseMoving()) { if (calcMovement()) { us.requestRedraw(); us.requestContinuousUpdate(true); _thrown = _allowThrow; } } else { flushMouseEventStack(); addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; } } else { flushMouseEventStack(); addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; } return true; } case(GUIEventAdapter::DRAG): case(GUIEventAdapter::SCROLL): { addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; return true; } case(GUIEventAdapter::MOVE): { return false; } case(GUIEventAdapter::KEYDOWN): if (ea.getKey()== GUIEventAdapter::KEY_Space) { flushMouseEventStack(); _thrown = false; home(ea,us); return true; } return false; case(GUIEventAdapter::FRAME): if (_thrown) { if (calcMovement()) us.requestRedraw(); } return false; default: return false; } return false; } //-------------------------------------------------------------------------------------------------- bool SphericalManipulator::isMouseMoving() { if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; const float velocity = 0.1f; float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); float len = sqrtf(dx*dx+dy*dy); float dt = _ga_t0->getTime()-_ga_t1->getTime(); return (len>dt*velocity); } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::flushMouseEventStack() { _ga_t1 = NULL; _ga_t0 = NULL; } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::addMouseEvent(const GUIEventAdapter& ea) { _ga_t1 = _ga_t0; _ga_t0 = &ea; } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::setByMatrix(const osg::Matrixd& matrix) { _center=osg::Vec3d(0,0,-_distance)*matrix; _heading=atan2(-matrix(0,0),matrix(0,1)); if(_rotationMode != MAP) { _elevation=asin(matrix(2,2)); } } //-------------------------------------------------------------------------------------------------- osg::Matrixd SphericalManipulator::getMatrix() const { return osg::Matrixd::translate(osg::Vec3d(0.0,0.0,_distance))* osg::Matrixd::rotate(PI_2-_elevation,1.0,0.0,0.0)* osg::Matrixd::rotate(PI_2+_heading,0.0,0.0,1.0)* osg::Matrixd::translate(_center); } //-------------------------------------------------------------------------------------------------- osg::Matrixd SphericalManipulator::getInverseMatrix() const { return osg::Matrixd::translate(-_center)* osg::Matrixd::rotate(PI_2+_heading,0.0,0.0,-1.0)* osg::Matrixd::rotate(PI_2-_elevation,-1.0,0.0,0.0)* osg::Matrixd::translate(osg::Vec3d(0.0,0.0,-_distance)); } //-------------------------------------------------------------------------------------------------- bool SphericalManipulator::calcMovement() { // mouse scroll is only a single event if (_ga_t0.get()==NULL) return false; float dx=0.0f; float dy=0.0f; unsigned int buttonMask=osgGA::GUIEventAdapter::NONE; if (_ga_t0->getEventType()==GUIEventAdapter::SCROLL) { dy = _ga_t0->getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP ? _zoomDelta : -_zoomDelta; buttonMask=GUIEventAdapter::SCROLL; } else { if (_ga_t1.get()==NULL) return false; dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); float distance = sqrtf(dx*dx + dy*dy); // return if movement is too fast, indicating an error in event values or change in screen. if (distance>0.5) { return false; } // return if there is no movement. if (distance==0.0f) { return false; } buttonMask = _ga_t1->getButtonMask(); } double throwScale = (_thrown && _ga_t0.valid() && _ga_t1.valid()) ? _delta_frame_time / (_ga_t0->getTime() - _ga_t1->getTime()) : 1.0; if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) { // rotate camera. if(_rotationMode == MAP) { float pxc = (_ga_t0->getXmax()+_ga_t0->getXmin())/2; float pyc = (_ga_t0->getYmax()+_ga_t0->getYmin())/2; float px0 = _ga_t0->getX(); float py0 = _ga_t0->getY(); float px1 = _ga_t1->getX(); float py1 = _ga_t1->getY(); float angle=atan2(py1-pyc,px1-pxc)-atan2(py0-pyc,px0-pxc); _heading+=throwScale*angle; if(_heading < -PI) _heading+=2*PI; else if(_heading > PI) _heading-=2*PI; } else { if((_rotationMode != ELEVATION) && ((_ga_t1->getModKeyMask() & GUIEventAdapter::MODKEY_SHIFT) == 0)) { _heading-=throwScale*dx*PI_2; if(_heading < 0) _heading+=2*PI; else if(_heading > 2*PI) _heading-=2*PI; } if((_rotationMode != HEADING) && ((_ga_t1->getModKeyMask() & GUIEventAdapter::MODKEY_ALT) == 0)) { _elevation-=throwScale*dy*osg::PI_4; // Only allows vertical rotation of 180deg if(_elevation < -osg::PI_2) _elevation=-osg::PI_2; else if(_elevation > osg::PI_2) _elevation=osg::PI_2; } } return true; } else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) { // pan model. float scale = -0.3f*_distance; osg::Matrix rotation_matrix; rotation_matrix=osg::Matrixd::rotate(_elevation,-1,0,0)*osg::Matrixd::rotate(PI_2+_heading,0,0,1); osg::Vec3d dv(throwScale*dx*scale,0,throwScale*dy*scale); _center += dv*rotation_matrix; return true; } else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON || _ga_t0->getEventType()==GUIEventAdapter::SCROLL) { // zoom model. double fd = _distance; double scale = 1.0+throwScale*dy; if(fd*scale > _modelScale*_minimumZoomScale) { _distance *= scale; } else { OSG_DEBUG << "Pushing forward"<getBound(),_modelScale,_homeDistance,_homeCenter); } //-------------------------------------------------------------------------------------------------- void SphericalManipulator::computeViewPosition(const osg::BoundingSphere& bound, double& scale,double& distance,osg::Vec3d& center) { scale=bound._radius; distance=3.5*bound._radius; if(distance <= 0) distance=1; center=bound._center; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgGA/KeySwitchMatrixManipulator.cpp0000644000175000017500000001470613151044751026700 0ustar albertoalberto#include #include using namespace osgGA; void KeySwitchMatrixManipulator::addMatrixManipulator(int key, std::string name, CameraManipulator *cm) { if(!cm) return; _manips[key]=std::make_pair(name,osg::ref_ptr(cm)); if(!_current) { _current=cm; _current->setHomePosition(_homeEye,_homeCenter,_homeUp,_autoComputeHomePosition); _current->setNode(0); _current->setCoordinateFrameCallback(getCoordinateFrameCallback()); _current->setByMatrix(getMatrix()); } } void KeySwitchMatrixManipulator::addNumberedMatrixManipulator(CameraManipulator *cm) { if(!cm) return; addMatrixManipulator('1'+_manips.size(),cm->className(),cm); } void KeySwitchMatrixManipulator::selectMatrixManipulator(unsigned int num) { unsigned int manipNo = 0; KeyManipMap::iterator itr; for(itr=_manips.begin(); manipNo!=num && itr!=_manips.end(); ++itr,++manipNo) { } if (itr!=_manips.end()) { itr->second.second->setHomePosition(_homeEye,_homeCenter,_homeUp,_autoComputeHomePosition); if (_current.valid()) { if ( !itr->second.second->getCoordinateFrameCallback() ) { itr->second.second->setCoordinateFrameCallback(_current->getCoordinateFrameCallback()); } if ( !itr->second.second->getNode() ) { itr->second.second->setNode(_current->getNode()); } itr->second.second->setByMatrix(_current->getMatrix()); } _current = itr->second.second; } } void KeySwitchMatrixManipulator::setNode(osg::Node* node) { for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->setNode(node); } } void KeySwitchMatrixManipulator::setHomePosition(const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up, bool autoComputeHomePosition) { CameraManipulator::setHomePosition(eye, center, up, autoComputeHomePosition); for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->setHomePosition(eye, center, up, autoComputeHomePosition); } } void KeySwitchMatrixManipulator::setAutoComputeHomePosition(bool flag) { _autoComputeHomePosition = flag; for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->setAutoComputeHomePosition(flag); } } void KeySwitchMatrixManipulator::computeHomePosition() { for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->computeHomePosition(); } } void KeySwitchMatrixManipulator::finishAnimation() { for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->finishAnimation(); } } void KeySwitchMatrixManipulator::home(const GUIEventAdapter& ee,GUIActionAdapter& aa) { // call home for all child manipulators // (this can not be done just for current manipulator, // because it is not possible to transfer some manipulator // settings across manipulators using just MatrixManipulator interface // (one problematic variable is for example OrbitManipulator::distance // that can not be passed by setByMatrix method), // thus we have to call home on all of them) for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->home(ee,aa); } } void KeySwitchMatrixManipulator::setCoordinateFrameCallback(CoordinateFrameCallback* cb) { _coordinateFrameCallback = cb; for(KeyManipMap::iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { itr->second.second->setCoordinateFrameCallback(cb); } } CameraManipulator* KeySwitchMatrixManipulator::getMatrixManipulatorWithIndex(unsigned int index) { unsigned i=0; for(KeyManipMap::iterator itr = _manips.begin(); itr != _manips.end(); ++itr, ++i) { if (i==index) return itr->second.second.get(); } return 0; } const CameraManipulator* KeySwitchMatrixManipulator::getMatrixManipulatorWithIndex(unsigned int index) const { unsigned i=0; for(KeyManipMap::const_iterator itr = _manips.begin(); itr != _manips.end(); ++itr, ++i) { if (i==index) return itr->second.second.get(); } return 0; } CameraManipulator* KeySwitchMatrixManipulator::getMatrixManipulatorWithKey(unsigned int key) { KeyManipMap::iterator itr = _manips.find(key); if (itr!=_manips.end()) return itr->second.second.get(); else return 0; } const CameraManipulator* KeySwitchMatrixManipulator::getMatrixManipulatorWithKey(unsigned int key) const { KeyManipMap::const_iterator itr = _manips.find(key); if (itr!=_manips.end()) return itr->second.second.get(); else return 0; } bool KeySwitchMatrixManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa) { if (!_current) return false; bool handled = false; if (!ea.getHandled() && ea.getEventType()==GUIEventAdapter::KEYDOWN) { KeyManipMap::iterator it=_manips.find(ea.getKey()); if(it != _manips.end()) { CameraManipulator* selectedManipulator = it->second.second.get(); if (selectedManipulator!=_current) { OSG_INFO<<"Switching to manipulator: "<second.first<getNode() ) { selectedManipulator->setNode(_current->getNode()); } selectedManipulator->setByMatrix(_current->getMatrix()); selectedManipulator->init(ea,aa); _current = selectedManipulator; } handled = true; } } return _current->handle(ea,aa) || handled; } void KeySwitchMatrixManipulator::getUsage(osg::ApplicationUsage& usage) const { for(KeyManipMap::const_iterator itr=_manips.begin(); itr!=_manips.end(); ++itr) { std::string key; key += (char)(itr->first); std::string explanation(std::string("Select '")+itr->second.first+std::string("' camera manipulator")); if (_current==itr->second.second) explanation += " (default)"; usage.addKeyboardMouseBinding(key,explanation); itr->second.second->getUsage(usage); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/0000755000175000017500000000000013151044751022125 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/PrecipitationEffect.cpp0000644000175000017500000007541413151044751026573 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgParticle; #define USE_LOCAL_SHADERS static float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; } PrecipitationEffect::PrecipitationEffect(): _previousFrameTime(FLT_MAX) { setNumChildrenRequiringUpdateTraversal(1); setUpGeometries(1024); rain(0.5); } PrecipitationEffect::PrecipitationEffect(const PrecipitationEffect& copy, const osg::CopyOp& copyop): osg::Node(copy,copyop), _previousFrameTime(FLT_MAX) { setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1); _wind = copy._wind; _particleSpeed = copy._particleSpeed; _particleSize = copy._particleSize; _particleColor = copy._particleColor; _maximumParticleDensity = copy._maximumParticleDensity; _cellSize = copy._cellSize; _nearTransition = copy._nearTransition; _farTransition = copy._farTransition; _fog = copy._fog.valid() ? dynamic_cast(copy._fog->clone(copyop)) : 0; _useFarLineSegments = copy._useFarLineSegments; _dirty = true; update(); } void PrecipitationEffect::rain(float intensity) { _wind.set(0.0f,0.0f,0.0f); _particleSpeed = -2.0f + -5.0f*intensity; _particleSize = 0.01 + 0.02*intensity; _particleColor = osg::Vec4(0.6, 0.6, 0.6, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0)* intensity; _maximumParticleDensity = intensity * 8.5f; _cellSize.set(5.0f / (0.25f+intensity), 5.0f / (0.25f+intensity), 5.0f); _nearTransition = 25.f; _farTransition = 100.0f - 60.0f*sqrtf(intensity); if (!_fog) _fog = new osg::Fog; _fog->setMode(osg::Fog::EXP); _fog->setDensity(0.005f*intensity); _fog->setColor(osg::Vec4(0.5, 0.5, 0.5, 1.0)); _useFarLineSegments = false; _dirty = true; update(); } void PrecipitationEffect::snow(float intensity) { _wind.set(0.0f,0.0f,0.0f); _particleSpeed = -0.75f - 0.25f*intensity; _particleSize = 0.02f + 0.03f*intensity; _particleColor = osg::Vec4(0.85f, 0.85f, 0.85f, 1.0f) - osg::Vec4(0.1f, 0.1f, 0.1f, 1.0f)* intensity; _maximumParticleDensity = intensity * 8.2f; _cellSize.set(5.0f / (0.25f+intensity), 5.0f / (0.25f+intensity), 5.0f); _nearTransition = 25.f; _farTransition = 100.0f - 60.0f*sqrtf(intensity); if (!_fog) _fog = new osg::Fog; _fog->setMode(osg::Fog::EXP); _fog->setDensity(0.01f*intensity); _fog->setColor(osg::Vec4(0.6, 0.6, 0.6, 1.0)); _useFarLineSegments = false; _dirty = true; update(); } void PrecipitationEffect::compileGLObjects(osg::RenderInfo& renderInfo) const { if (_quadGeometry.valid()) { _quadGeometry->compileGLObjects(renderInfo); if (_quadGeometry->getStateSet()) _quadGeometry->getStateSet()->compileGLObjects(*renderInfo.getState()); } if (_lineGeometry.valid()) { _lineGeometry->compileGLObjects(renderInfo); if (_lineGeometry->getStateSet()) _lineGeometry->getStateSet()->compileGLObjects(*renderInfo.getState()); } if (_pointGeometry.valid()) { _pointGeometry->compileGLObjects(renderInfo); if (_pointGeometry->getStateSet()) _pointGeometry->getStateSet()->compileGLObjects(*renderInfo.getState()); } } void PrecipitationEffect::traverse(osg::NodeVisitor& nv) { if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { if (_dirty) update(); if (nv.getFrameStamp()) { double currentTime = nv.getFrameStamp()->getSimulationTime(); if (_previousFrameTime==FLT_MAX) _previousFrameTime = currentTime; double delta = currentTime - _previousFrameTime; _origin += _wind * delta; _previousFrameTime = currentTime; } return; } if (nv.getVisitorType() == osg::NodeVisitor::NODE_VISITOR) { if (_dirty) update(); osgUtil::GLObjectsVisitor* globjVisitor = dynamic_cast(&nv); if (globjVisitor) { if (globjVisitor->getMode() & osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES) { compileGLObjects(globjVisitor->getRenderInfo()); } } return; } if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR) { return; } osgUtil::CullVisitor* cv = dynamic_cast(&nv); if (!cv) { return; } ViewIdentifier viewIndentifier(cv, nv.getNodePath()); { PrecipitationDrawableSet* precipitationDrawableSet = 0; { OpenThreads::ScopedLock lock(_mutex); precipitationDrawableSet = &(_viewDrawableMap[viewIndentifier]); if (!precipitationDrawableSet->_quadPrecipitationDrawable) { precipitationDrawableSet->_quadPrecipitationDrawable = new PrecipitationDrawable; precipitationDrawableSet->_quadPrecipitationDrawable->setRequiresPreviousMatrix(true); precipitationDrawableSet->_quadPrecipitationDrawable->setGeometry(_quadGeometry.get()); precipitationDrawableSet->_quadPrecipitationDrawable->setStateSet(_quadStateSet.get()); precipitationDrawableSet->_quadPrecipitationDrawable->setDrawType(GL_QUADS); precipitationDrawableSet->_linePrecipitationDrawable = new PrecipitationDrawable; precipitationDrawableSet->_linePrecipitationDrawable->setRequiresPreviousMatrix(true); precipitationDrawableSet->_linePrecipitationDrawable->setGeometry(_lineGeometry.get()); precipitationDrawableSet->_linePrecipitationDrawable->setStateSet(_lineStateSet.get()); precipitationDrawableSet->_linePrecipitationDrawable->setDrawType(GL_LINES); precipitationDrawableSet->_pointPrecipitationDrawable = new PrecipitationDrawable; precipitationDrawableSet->_pointPrecipitationDrawable->setRequiresPreviousMatrix(false); precipitationDrawableSet->_pointPrecipitationDrawable->setGeometry(_pointGeometry.get()); precipitationDrawableSet->_pointPrecipitationDrawable->setStateSet(_pointStateSet.get()); precipitationDrawableSet->_pointPrecipitationDrawable->setDrawType(GL_POINTS); } } cull(*precipitationDrawableSet, cv); cv->pushStateSet(_stateset.get()); float depth = 0.0f; if (!precipitationDrawableSet->_quadPrecipitationDrawable->getCurrentCellMatrixMap().empty()) { cv->pushStateSet(precipitationDrawableSet->_quadPrecipitationDrawable->getStateSet()); cv->addDrawableAndDepth(precipitationDrawableSet->_quadPrecipitationDrawable.get(),cv->getModelViewMatrix(),depth); cv->popStateSet(); } if (!precipitationDrawableSet->_linePrecipitationDrawable->getCurrentCellMatrixMap().empty()) { cv->pushStateSet(precipitationDrawableSet->_linePrecipitationDrawable->getStateSet()); cv->addDrawableAndDepth(precipitationDrawableSet->_linePrecipitationDrawable.get(),cv->getModelViewMatrix(),depth); cv->popStateSet(); } if (!precipitationDrawableSet->_pointPrecipitationDrawable->getCurrentCellMatrixMap().empty()) { cv->pushStateSet(precipitationDrawableSet->_pointPrecipitationDrawable->getStateSet()); cv->addDrawableAndDepth(precipitationDrawableSet->_pointPrecipitationDrawable.get(),cv->getModelViewMatrix(),depth); cv->popStateSet(); } cv->popStateSet(); } } void PrecipitationEffect::update() { _dirty = false; OSG_INFO<<"PrecipitationEffect::update()"<setMode(GL_LIGHTING, osg::StateAttribute::OFF); _stateset->setMode(GL_BLEND, osg::StateAttribute::ON); osg::Texture2D* texture = new osg::Texture2D(createSpotLightImage(osg::Vec4(1.0f,1.0f,1.0f,1.0f),osg::Vec4(1.0f,1.0f,1.0f,0.0f),32,1.0)); _stateset->setTextureAttribute(0, texture); } if (!_inversePeriodUniform) { _inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/_period); _stateset->addUniform(_inversePeriodUniform.get()); } else _inversePeriodUniform->set(1.0f/_period); if (!_particleColorUniform) { _particleColorUniform = new osg::Uniform("particleColour", _particleColor); _stateset->addUniform(_particleColorUniform.get()); } else _particleColorUniform->set(_particleColor); if (!_particleSizeUniform) { _particleSizeUniform = new osg::Uniform("particleSize", _particleSize); _stateset->addUniform(_particleSizeUniform.get()); } else _particleSizeUniform->set(_particleSize); } } void PrecipitationEffect::createGeometry(unsigned int numParticles, osg::Geometry* quad_geometry, osg::Geometry* line_geometry, osg::Geometry* point_geometry) { // particle corner offsets osg::Vec2 offset00(0.0f,0.0f); osg::Vec2 offset10(1.0f,0.0f); osg::Vec2 offset01(0.0f,1.0f); osg::Vec2 offset11(1.0f,1.0f); osg::Vec2 offset0(0.5f,0.0f); osg::Vec2 offset1(0.5f,1.0f); osg::Vec2 offset(0.5f,0.5f); // configure quad_geometry; osg::Vec3Array* quad_vertices = 0; osg::Vec2Array* quad_offsets = 0; if (quad_geometry) { quad_geometry->setName("quad"); quad_vertices = new osg::Vec3Array(numParticles*4); quad_offsets = new osg::Vec2Array(numParticles*4); quad_geometry->setVertexArray(quad_vertices); quad_geometry->setTexCoordArray(0, quad_offsets); } // configure line_geometry; osg::Vec3Array* line_vertices = 0; osg::Vec2Array* line_offsets = 0; if (line_geometry) { line_geometry->setName("line"); line_vertices = new osg::Vec3Array(numParticles*2); line_offsets = new osg::Vec2Array(numParticles*2); line_geometry->setVertexArray(line_vertices); line_geometry->setTexCoordArray(0, line_offsets); } // configure point_geometry; osg::Vec3Array* point_vertices = 0; osg::Vec2Array* point_offsets = 0; if (point_geometry) { point_geometry->setName("point"); point_vertices = new osg::Vec3Array(numParticles); point_offsets = new osg::Vec2Array(numParticles); point_geometry->setVertexArray(point_vertices); point_geometry->setTexCoordArray(0, point_offsets); } // set up vertex attribute data. for(unsigned int i=0; i< numParticles; ++i) { osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f)); // quad particles if (quad_vertices) { (*quad_vertices)[i*4] = pos; (*quad_vertices)[i*4+1] = pos; (*quad_vertices)[i*4+2] = pos; (*quad_vertices)[i*4+3] = pos; (*quad_offsets)[i*4] = offset00; (*quad_offsets)[i*4+1] = offset01; (*quad_offsets)[i*4+2] = offset11; (*quad_offsets)[i*4+3] = offset10; } // line particles if (line_vertices) { (*line_vertices)[i*2] = pos; (*line_vertices)[i*2+1] = pos; (*line_offsets)[i*2] = offset0; (*line_offsets)[i*2+1] = offset1; } // point particles if (point_vertices) { (*point_vertices)[i] = pos; (*point_offsets)[i] = offset; } } } void PrecipitationEffect::setUpGeometries(unsigned int numParticles) { unsigned int quadRenderBin = 13; unsigned int lineRenderBin = 12; unsigned int pointRenderBin = 11; OSG_INFO<<"PrecipitationEffect::setUpGeometries("<getVertexArray()->getNumElements() != 4*numParticles) { _quadGeometry = new osg::Geometry; _quadGeometry->setUseVertexBufferObjects(true); needGeometryRebuild = true; } if (!_lineGeometry || _lineGeometry->getVertexArray()->getNumElements() != 2*numParticles) { _lineGeometry = new osg::Geometry; _lineGeometry->setUseVertexBufferObjects(true); needGeometryRebuild = true; } if (!_pointGeometry || _pointGeometry->getVertexArray()->getNumElements() != numParticles) { _pointGeometry = new osg::Geometry; _pointGeometry->setUseVertexBufferObjects(true); needGeometryRebuild = true; } if (needGeometryRebuild) { createGeometry(numParticles, _quadGeometry.get(), _lineGeometry.get(), _pointGeometry.get()); } if (!_quadStateSet) { _quadStateSet = new osg::StateSet; osg::Program* program = new osg::Program; _quadStateSet->setAttribute(program); _quadStateSet->setRenderBinDetails(quadRenderBin,"DepthSortedBin"); #ifdef USE_LOCAL_SHADERS char vertexShaderSource[] = "uniform float inversePeriod;\n" "uniform vec4 particleColour;\n" "uniform float particleSize;\n" "\n" "uniform float osg_SimulationTime;\n" "uniform float osg_DeltaSimulationTime;\n" "\n" "varying vec4 colour;\n" "varying vec2 texCoord;\n" "\n" "void main(void)\n" "{\n" " float offset = gl_Vertex.z;\n" " float startTime = gl_MultiTexCoord1.x;\n" " texCoord = gl_MultiTexCoord0.xy;\n" "\n" " vec4 v_previous = gl_Vertex;\n" " v_previous.z = fract( (osg_SimulationTime - startTime)*inversePeriod - offset);\n" " \n" " vec4 v_current = v_previous;\n" " v_current.z += (osg_DeltaSimulationTime*inversePeriod);\n" " \n" "\n" " colour = particleColour;\n" " \n" " vec4 v1 = gl_ModelViewMatrix * v_current;\n" " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" " \n" " vec3 dv = v2.xyz - v1.xyz;\n" " \n" " vec2 dv_normalized = normalize(dv.xy);\n" " dv.xy += dv_normalized * particleSize;\n" " vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize;\n" " \n" " float area = length(dv.xy);\n" " colour.a = 0.05+(particleSize)/area;\n" " \n" "\n" " v1.xyz += dv*texCoord.y;\n" " v1.xy += dp*texCoord.x;\n" " \n" " gl_Position = gl_ProjectionMatrix * v1;\n" " gl_ClipVertex = v1;\n" "}\n"; char fragmentShaderSource[] = "uniform sampler2D baseTexture;\n" "varying vec2 texCoord;\n" "varying vec4 colour;\n" "\n" "void main (void)\n" "{\n" " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" "}\n"; program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); #else // get shaders from source program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert"))); program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); #endif } if (!_lineStateSet) { _lineStateSet = new osg::StateSet; osg::Program* program = new osg::Program; _lineStateSet->setAttribute(program); _lineStateSet->setRenderBinDetails(lineRenderBin,"DepthSortedBin"); #ifdef USE_LOCAL_SHADERS char vertexShaderSource[] = "uniform float inversePeriod;\n" "uniform vec4 particleColour;\n" "uniform float particleSize;\n" "\n" "uniform float osg_SimulationTime;\n" "uniform float osg_DeltaSimulationTime;\n" "uniform mat4 previousModelViewMatrix;\n" "\n" "varying vec4 colour;\n" "varying vec2 texCoord;\n" "\n" "void main(void)\n" "{\n" " float offset = gl_Vertex.z;\n" " float startTime = gl_MultiTexCoord1.x;\n" " texCoord = gl_MultiTexCoord0.xy;\n" "\n" " vec4 v_previous = gl_Vertex;\n" " v_previous.z = fract( (osg_SimulationTime - startTime)*inversePeriod - offset);\n" " \n" " vec4 v_current = v_previous;\n" " v_current.z += (osg_DeltaSimulationTime*inversePeriod);\n" " \n" " colour = particleColour;\n" " \n" " vec4 v1 = gl_ModelViewMatrix * v_current;\n" " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" " \n" " vec3 dv = v2.xyz - v1.xyz;\n" " \n" " vec2 dv_normalized = normalize(dv.xy);\n" " dv.xy += dv_normalized * particleSize;\n" " \n" " float area = length(dv.xy);\n" " colour.a = (particleSize)/area;\n" " \n" " v1.xyz += dv*texCoord.y;\n" " \n" " gl_Position = gl_ProjectionMatrix * v1;\n" " gl_ClipVertex = v1;\n" "}\n"; char fragmentShaderSource[] = "uniform sampler2D baseTexture;\n" "varying vec2 texCoord;\n" "varying vec4 colour;\n" "\n" "void main (void)\n" "{\n" " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" "}\n"; program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); #else // get shaders from source program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert"))); program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); #endif } if (!_pointStateSet) { _pointStateSet = new osg::StateSet; osg::Program* program = new osg::Program; _pointStateSet->setAttribute(program); #ifdef USE_LOCAL_SHADERS char vertexShaderSource[] = "uniform float inversePeriod;\n" "uniform vec4 particleColour;\n" "uniform float particleSize;\n" "\n" "uniform float osg_SimulationTime;\n" "\n" "varying vec4 colour;\n" "\n" "void main(void)\n" "{\n" " float offset = gl_Vertex.z;\n" " float startTime = gl_MultiTexCoord1.x;\n" "\n" " vec4 v_current = gl_Vertex;\n" " v_current.z = fract( (osg_SimulationTime - startTime)*inversePeriod - offset);\n" " \n" " colour = particleColour;\n" "\n" " gl_Position = gl_ModelViewProjectionMatrix * v_current;\n" "\n" " float pointSize = abs(1280.0*particleSize / gl_Position.w);\n" "\n" " //gl_PointSize = max(ceil(pointSize),2);\n" " gl_PointSize = ceil(pointSize);\n" " \n" " colour.a = 0.05+(pointSize*pointSize)/(gl_PointSize*gl_PointSize);\n" " gl_ClipVertex = gl_ModelViewMatrix * v_current;\n" "}\n"; char fragmentShaderSource[] = "uniform sampler2D baseTexture;\n" "varying vec4 colour;\n" "\n" "void main (void)\n" "{\n" " gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0].xy);\n" "}\n"; program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); #else // get shaders from source program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert"))); program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("point_rain.frag"))); #endif /// Setup the point sprites osg::PointSprite *sprite = new osg::PointSprite(); _pointStateSet->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON); #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) _pointStateSet->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON); #else OSG_NOTICE<<"Warning: ParticleEffect::setUpGeometries(..) not fully implemented."<setRenderBinDetails(pointRenderBin,"DepthSortedBin"); } } void PrecipitationEffect::cull(PrecipitationDrawableSet& pds, osgUtil::CullVisitor* cv) const { #ifdef DO_TIMING osg::Timer_t startTick = osg::Timer::instance()->tick(); #endif float cellVolume = _cellSize.x() * _cellSize.y() * _cellSize.z(); int numberOfParticles = (int)(_maximumParticleDensity * cellVolume); if (numberOfParticles==0) return; pds._quadPrecipitationDrawable->setNumberOfVertices(numberOfParticles*4); pds._linePrecipitationDrawable->setNumberOfVertices(numberOfParticles*2); pds._pointPrecipitationDrawable->setNumberOfVertices(numberOfParticles); pds._quadPrecipitationDrawable->newFrame(); pds._linePrecipitationDrawable->newFrame(); pds._pointPrecipitationDrawable->newFrame(); osg::Matrix inverse_modelview; inverse_modelview.invert(*(cv->getModelViewMatrix())); osg::Vec3 eyeLocal = osg::Vec3(0.0f,0.0f,0.0f) * inverse_modelview; //OSG_NOTICE<<" eyeLocal "<getProjectionMatrix())); frustum.transformProvidingInverse(*(cv->getModelViewMatrix())); float i_delta = _farTransition * _inverse_du.x(); float j_delta = _farTransition * _inverse_dv.y(); float k_delta = 1;//_nearTransition * _inverse_dw.z(); int i_min = (int)floor(eye_i - i_delta); int j_min = (int)floor(eye_j - j_delta); int k_min = (int)floor(eye_k - k_delta); int i_max = (int)ceil(eye_i + i_delta); int j_max = (int)ceil(eye_j + j_delta); int k_max = (int)ceil(eye_k + k_delta); //OSG_NOTICE<<"i_delta="<delta_m(startTick,endTick)<<"ms numTested="<getCurrentCellMatrixMap().size()<<" lines "<getCurrentCellMatrixMap().size()<<" points "<getCurrentCellMatrixMap().size()<getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)]; mstp.depth = distance; mstp.startTime = startTime; mymodelview = &mstp.modelview; } else if (distance <= _farTransition) { if (_useFarLineSegments) { PrecipitationDrawable::DepthMatrixStartTime& mstp = pds._linePrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)]; mstp.depth = distance; mstp.startTime = startTime; mymodelview = &mstp.modelview; } else { PrecipitationDrawable::DepthMatrixStartTime& mstp = pds._pointPrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)]; mstp.depth = distance; mstp.startTime = startTime; mymodelview = &mstp.modelview; } } else { return false; } *mymodelview = *(cv->getModelViewMatrix()); mymodelview->preMultTranslate(position); mymodelview->preMultScale(scale); cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb); return true; } ///////////////////////////////////////////////////////////////////////////////////////////////////// // // Precipitation Drawable // //////////////////////////////////////////////////////////////////////////////////////////////////// PrecipitationEffect::PrecipitationDrawable::PrecipitationDrawable(): _requiresPreviousMatrix(true), _drawType(GL_QUADS), _numberOfVertices(0) { setSupportsDisplayList(false); } PrecipitationEffect::PrecipitationDrawable::PrecipitationDrawable(const PrecipitationDrawable& copy, const osg::CopyOp& copyop): osg::Drawable(copy,copyop), _requiresPreviousMatrix(copy._requiresPreviousMatrix), _geometry(copy._geometry), _drawType(copy._drawType), _numberOfVertices(copy._numberOfVertices) { } void PrecipitationEffect::PrecipitationDrawable::drawImplementation(osg::RenderInfo& renderInfo) const { #if defined(OSG_GL_MATRICES_AVAILABLE) if (!_geometry) return; const osg::GLExtensions* extensions = renderInfo.getState()->get(); // save OpenGL matrices glPushMatrix(); if (_requiresPreviousMatrix) { renderInfo.getState()->setActiveTextureUnit(0); glMatrixMode( GL_TEXTURE ); glPushMatrix(); } typedef std::vector DepthMatrixStartTimeVector; DepthMatrixStartTimeVector orderedEntries; orderedEntries.reserve(_currentCellMatrixMap.size()); for(CellMatrixMap::const_iterator citr = _currentCellMatrixMap.begin(); citr != _currentCellMatrixMap.end(); ++citr) { orderedEntries.push_back(&(*citr)); } std::sort(orderedEntries.begin(),orderedEntries.end(),LessFunctor()); for(DepthMatrixStartTimeVector::reverse_iterator itr = orderedEntries.rbegin(); itr != orderedEntries.rend(); ++itr) { extensions->glMultiTexCoord1f(GL_TEXTURE0+1, (*itr)->second.startTime); // load cells current modelview matrix if (_requiresPreviousMatrix) { glMatrixMode( GL_MODELVIEW ); glLoadMatrix((*itr)->second.modelview.ptr()); CellMatrixMap::const_iterator pitr = _previousCellMatrixMap.find((*itr)->first); if (pitr != _previousCellMatrixMap.end()) { // load previous frame modelview matrix for motion blurr effect glMatrixMode( GL_TEXTURE ); glLoadMatrix(pitr->second.modelview.ptr()); } else { // use current modelview matrix as "previous" frame value, cancelling motion blurr effect glMatrixMode( GL_TEXTURE ); glLoadMatrix((*itr)->second.modelview.ptr()); } } else { glLoadMatrix((*itr)->second.modelview.ptr()); } _geometry->draw(renderInfo); unsigned int numVertices = osg::minimum(_geometry->getVertexArray()->getNumElements(), _numberOfVertices); glDrawArrays(_drawType, 0, numVertices); } // restore OpenGL matrices if (_requiresPreviousMatrix) { glPopMatrix(); glMatrixMode( GL_MODELVIEW ); } glPopMatrix(); #else OSG_NOTICE<<"Warning: ParticleEffect::drawImplementation(..) not fully implemented."< osgParticle::FluidProgram::FluidProgram(): Program() { setFluidToAir(); } osgParticle::FluidProgram::FluidProgram(const FluidProgram& copy, const osg::CopyOp& copyop): Program(copy, copyop), _acceleration(copy._acceleration), _viscosity(copy._viscosity), _density(copy._density), _wind(copy._wind), _viscosityCoefficient(copy._viscosityCoefficient), _densityCoefficient(copy._densityCoefficient) { } void osgParticle::FluidProgram::execute(double dt) { const float four_over_three = 4.0f/3.0f; ParticleSystem* ps = getParticleSystem(); int n = ps->numParticles(); for (int i=0; igetParticle(i); if (particle->isAlive()) { float radius = particle->getRadius(); float Area = osg::PI*radius*radius; float Volume = Area*radius*four_over_three; // compute force due to gravity + boyancy of displacing the fluid that the particle is emersed in. osg::Vec3 accel_gravity = _acceleration * ((particle->getMass() - _density*Volume) * particle->getMassInv()); // compute force due to friction osg::Vec3 relative_wind = particle->getVelocity()-_wind; osg::Vec3 wind_force = - relative_wind * Area * (_viscosityCoefficient + _densityCoefficient*relative_wind.length()); osg::Vec3 wind_accel = wind_force * particle->getMassInv(); double compenstated_dt = dt; if (relative_wind.length2() < dt*dt*wind_accel.length2()) { // OSG_NOTICE<<"** Could be critical: dt="< #include #include #include #include #include using namespace osgParticle; SmokeEffect::SmokeEffect(bool automaticSetup): ParticleEffect(automaticSetup) { setDefaults(); _position.set(0.0f,0.0f,0.0f); _scale = 1.0f; _intensity = 1.0f; _emitterDuration = 65.0; _defaultParticleTemplate.setLifeTime(5.0*_scale); if (_automaticSetup) buildEffect(); } SmokeEffect::SmokeEffect(const osg::Vec3& position, float scale, float intensity) { setDefaults(); _position = position; _scale = scale; _intensity = intensity; _emitterDuration = 65.0; _defaultParticleTemplate.setLifeTime(5.0*_scale); if (_automaticSetup) buildEffect(); } SmokeEffect::SmokeEffect(const SmokeEffect& copy, const osg::CopyOp& copyop): ParticleEffect(copy,copyop) { if (_automaticSetup) buildEffect(); } void SmokeEffect::setDefaults() { ParticleEffect::setDefaults(); _textureFileName = "Images/smoke.rgb"; _emitterDuration = 65.0; // set up unit particle. _defaultParticleTemplate.setLifeTime(5.0*_scale); _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 2.0f)); _defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.1f, 1.0f)); _defaultParticleTemplate.setColorRange(osgParticle::rangev4( osg::Vec4(1, 1.0f, 1.0f, 1.0f), osg::Vec4(1, 1.0f, 1.f, 0.0f))); } void SmokeEffect::setUpEmitterAndProgram() { // set up particle system if (!_particleSystem) { _particleSystem = new osgParticle::ParticleSystem; } if (_particleSystem.valid()) { _particleSystem->setDefaultAttributes(_textureFileName, false, false); osgParticle::Particle& ptemplate = _particleSystem->getDefaultParticleTemplate(); float radius = 0.5f*_scale; float density = 1.0f; // 1.0kg/m^3 ptemplate.setLifeTime(_defaultParticleTemplate.getLifeTime()); // the following ranges set the envelope of the respective // graphical properties in time. ptemplate.setSizeRange(osgParticle::rangef(radius*_defaultParticleTemplate.getSizeRange().minimum, radius*_defaultParticleTemplate.getSizeRange().maximum)); ptemplate.setAlphaRange(_defaultParticleTemplate.getAlphaRange()); ptemplate.setColorRange(_defaultParticleTemplate.getColorRange()); // these are physical properties of the particle ptemplate.setRadius(radius); ptemplate.setMass(density*radius*radius*radius*osg::PI*4.0f/3.0f); } // set up emitter if (!_emitter) { _emitter = new osgParticle::ModularEmitter; _emitter->setNumParticlesToCreateMovementCompensationRatio(1.5f); _emitter->setCounter(new osgParticle::RandomRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter); } if (_emitter.valid()) { _emitter->setParticleSystem(_particleSystem.get()); _emitter->setReferenceFrame(_useLocalParticleSystem? osgParticle::ParticleProcessor::ABSOLUTE_RF: osgParticle::ParticleProcessor::RELATIVE_RF); _emitter->setStartTime(_startTime); _emitter->setLifeTime(_emitterDuration); _emitter->setEndless(false); osgParticle::RandomRateCounter* counter = dynamic_cast(_emitter->getCounter()); if (counter) { counter->setRateRange(3*_intensity,5*_intensity); } osgParticle::SectorPlacer* placer = dynamic_cast(_emitter->getPlacer()); if (placer) { placer->setCenter(_position); placer->setRadiusRange(0.0f*_scale,0.25f*_scale); } osgParticle::RadialShooter* shooter = dynamic_cast(_emitter->getShooter()); if (shooter) { shooter->setThetaRange(0.0f, osg::PI_4); shooter->setInitialSpeedRange(0.0f*_scale,0.0f*_scale); } } // set up program. if (!_program) { _program = new osgParticle::FluidProgram; } if (_program.valid()) { _program->setParticleSystem(_particleSystem.get()); _program->setWind(_wind); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/SinkOperator.cpp0000644000175000017500000000731413151044751025256 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // Written by Wang Rui, (C) 2010 #include #include #include #define SINK_EPSILON 1e-3 using namespace osgParticle; void SinkOperator::beginOperate( Program* prg ) { // Don't transform domains if they are used for sinking velocities if ( _sinkTarget==SINK_POSITION ) DomainOperator::beginOperate(prg ); } void SinkOperator::handlePoint( const Domain& domain, Particle* P, double /*dt*/ ) { const osg::Vec3& value = getValue(P); kill( P, (domain.v1==value) ); } void SinkOperator::handleLineSegment( const Domain& domain, Particle* P, double /*dt*/ ) { const osg::Vec3& value = getValue(P); osg::Vec3 offset = value - domain.v1, normal = domain.v2 - domain.v1; normal.normalize(); float diff = fabs(normal*offset - offset.length()) / domain.r1; kill( P, (diffSINK_EPSILON ) insideDomain = false; else { float upos = offset * domain.s1; float vpos = offset * domain.s2; insideDomain = !(upos<0.0f || vpos<0.0f || (upos+vpos)>1.0f); } kill( P, insideDomain ); } void SinkOperator::handleRectangle( const Domain& domain, Particle* P, double /*dt*/ ) { bool insideDomain = false; const osg::Vec3& value = getValue(P); osg::Vec3 offset = value - domain.v1; if ( offset*domain.plane.getNormal()>SINK_EPSILON ) insideDomain = false; else { float upos = offset * domain.s1; float vpos = offset * domain.s2; insideDomain = !(upos<0.0f || upos>1.0f || vpos<0.0f || vpos>1.0f); } kill( P, insideDomain ); } void SinkOperator::handlePlane( const Domain& domain, Particle* P, double /*dt*/ ) { const osg::Vec3& value = getValue(P); bool insideDomain = (domain.plane.getNormal()*value>=-domain.plane[3]); kill( P, insideDomain ); } void SinkOperator::handleSphere( const Domain& domain, Particle* P, double /*dt*/ ) { const osg::Vec3& value = getValue(P); float r = (value - domain.v1).length(); kill( P, (r<=domain.r1) ); } void SinkOperator::handleBox( const Domain& domain, Particle* P, double /*dt*/ ) { const osg::Vec3& value = getValue(P); bool insideDomain = !( (value.x() < domain.v1.x()) || (value.x() > domain.v2.x()) || (value.y() < domain.v1.y()) || (value.y() > domain.v2.y()) || (value.z() < domain.v1.z()) || (value.z() > domain.v2.z()) ); kill( P, insideDomain ); } void SinkOperator::handleDisk( const Domain& domain, Particle* P, double /*dt*/ ) { bool insideDomain = false; const osg::Vec3& value = getValue(P); osg::Vec3 offset = value - domain.v1; if ( offset*domain.v2>SINK_EPSILON ) insideDomain = false; else { float length = offset.length(); insideDomain = (length<=domain.r1 && length>=domain.r2); } kill( P, insideDomain ); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ModularProgram.cpp0000644000175000017500000000156113151044751025567 0ustar albertoalberto#include #include #include #include osgParticle::ModularProgram::ModularProgram() : Program() { } osgParticle::ModularProgram::ModularProgram(const ModularProgram& copy, const osg::CopyOp& copyop) : Program(copy, copyop) { Operator_vector::const_iterator ci; for (ci=copy._operators.begin(); ci!=copy._operators.end(); ++ci) { _operators.push_back(static_cast(copyop(ci->get()))); } } void osgParticle::ModularProgram::execute(double dt) { Operator_vector::iterator ci; Operator_vector::iterator ci_end = _operators.end(); ParticleSystem* ps = getParticleSystem(); for (ci=_operators.begin(); ci!=ci_end; ++ci) { (*ci)->beginOperate(this); (*ci)->operateParticles(ps, dt); (*ci)->endOperate(); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/SmokeTrailEffect.cpp0000644000175000017500000001236313151044751026025 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include using namespace osgParticle; SmokeTrailEffect::SmokeTrailEffect(bool automaticSetup): ParticleEffect(automaticSetup) { setDefaults(); _position.set(0.0f,0.0f,0.0f); _scale = 1.0f; _intensity = 1.0f; _emitterDuration = 65.0; _defaultParticleTemplate.setLifeTime(5.0*_scale); if (_automaticSetup) buildEffect(); } SmokeTrailEffect::SmokeTrailEffect(const osg::Vec3& position, float scale, float intensity) { setDefaults(); _position = position; _scale = scale; _intensity = intensity; _emitterDuration = 65.0; _defaultParticleTemplate.setLifeTime(5.0*_scale); if (_automaticSetup) buildEffect(); } SmokeTrailEffect::SmokeTrailEffect(const SmokeTrailEffect& copy, const osg::CopyOp& copyop): ParticleEffect(copy,copyop) { if (_automaticSetup) buildEffect(); } void SmokeTrailEffect::setDefaults() { ParticleEffect::setDefaults(); _textureFileName = "Images/continous_smoke.rgb"; _emitterDuration = 65.0; // set up unit particle. _defaultParticleTemplate.setLifeTime(5.0*_scale); _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 2.0f)); _defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.7f, 1.0f)); _defaultParticleTemplate.setColorRange(osgParticle::rangev4( osg::Vec4(1, 1.0f, 1.0f, 1.0f), osg::Vec4(1, 1.0f, 1.f, 0.0f))); } void SmokeTrailEffect::setUpEmitterAndProgram() { // set up particle system if (!_particleSystem) { _particleSystem = new osgParticle::ConnectedParticleSystem; } if (_particleSystem.valid()) { _particleSystem->setDefaultAttributes(_textureFileName, false, false); osgParticle::Particle& ptemplate = _particleSystem->getDefaultParticleTemplate(); float radius = 0.5f*_scale; float density = 1.0f; // 1.0kg/m^3 ptemplate.setLifeTime(_defaultParticleTemplate.getLifeTime()); // the following ranges set the envelope of the respective // graphical properties in time. ptemplate.setSizeRange(osgParticle::rangef(radius*_defaultParticleTemplate.getSizeRange().minimum, radius*_defaultParticleTemplate.getSizeRange().maximum)); ptemplate.setAlphaRange(_defaultParticleTemplate.getAlphaRange()); ptemplate.setColorRange(_defaultParticleTemplate.getColorRange()); // these are physical properties of the particle ptemplate.setRadius(radius); ptemplate.setMass(density*radius*radius*radius*osg::PI*4.0f/3.0f); } // set up emitter if (!_emitter) { _emitter = new osgParticle::ModularEmitter; _emitter->setCounter(new osgParticle::ConstantRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter); } if (_emitter.valid()) { _emitter->setParticleSystem(_particleSystem.get()); _emitter->setReferenceFrame(_useLocalParticleSystem? osgParticle::ParticleProcessor::ABSOLUTE_RF: osgParticle::ParticleProcessor::RELATIVE_RF); _emitter->setStartTime(_startTime); _emitter->setLifeTime(_emitterDuration); _emitter->setEndless(false); osgParticle::ConstantRateCounter* counter = dynamic_cast(_emitter->getCounter()); if (counter) { counter->setMinimumNumberOfParticlesToCreate(1); counter->setNumberOfParticlesPerSecondToCreate(0.0); } osgParticle::SectorPlacer* placer = dynamic_cast(_emitter->getPlacer()); if (placer) { placer->setCenter(_position); placer->setRadiusRange(0.0f*_scale,0.0f*_scale); } osgParticle::RadialShooter* shooter = dynamic_cast(_emitter->getShooter()); if (shooter) { shooter->setThetaRange(0.0f, 0.0f); shooter->setInitialSpeedRange(0.0f*_scale,0.0f*_scale); } } // set up program. if (!_program) { _program = new osgParticle::FluidProgram; } if (_program.valid()) { _program->setParticleSystem(_particleSystem.get()); _program->setWind(_wind); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ModularEmitter.cpp0000644000175000017500000000763613151044751025602 0ustar albertoalberto#include #include #include #include osgParticle::ModularEmitter::ModularEmitter() : Emitter(), _numParticleToCreateMovementCompensationRatio(0.0f), _counter(new RandomRateCounter), _placer(new PointPlacer), _shooter(new RadialShooter) { } osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter& copy, const osg::CopyOp& copyop): Emitter(copy, copyop), _numParticleToCreateMovementCompensationRatio(copy._numParticleToCreateMovementCompensationRatio), _counter(static_cast(copyop(copy._counter.get()))), _placer(static_cast(copyop(copy._placer.get()))), _shooter(static_cast(copyop(copy._shooter.get()))) { } void osgParticle::ModularEmitter::emitParticles(double dt) { ConnectedParticleSystem* cps = dynamic_cast(getParticleSystem()); osg::Matrix worldToPs; osg::MatrixList worldMats = getParticleSystem()->getWorldMatrices(); if (!worldMats.empty()) { const osg::Matrix psToWorld = worldMats[0]; worldToPs = osg::Matrix::inverse(psToWorld); } if (getReferenceFrame() == RELATIVE_RF) { const osg::Matrix& ltw = getLocalToWorldMatrix(); const osg::Matrix& previous_ltw = getPreviousLocalToWorldMatrix(); const osg::Matrix emitterToPs = ltw * worldToPs; const osg::Matrix prevEmitterToPs = previous_ltw * worldToPs; int n = _counter->numParticlesToCreate(dt); if (_numParticleToCreateMovementCompensationRatio>0.0f) { // compute the distance moved between frames const osg::Vec3d controlPosition = osg::Vec3d(_placer->getControlPosition()); osg::Vec3d previousPosition = controlPosition * previous_ltw; osg::Vec3d currentPosition = controlPosition * ltw; float distance = (currentPosition-previousPosition).length(); float size = getUseDefaultTemplate() ? getParticleSystem()->getDefaultParticleTemplate().getSizeRange().minimum : getParticleTemplate().getSizeRange().minimum; float num_extra_samples = _numParticleToCreateMovementCompensationRatio*distance/size; float rounded_down = floor(num_extra_samples); float remainder = num_extra_samples-rounded_down; n = osg::maximum(n, int(rounded_down) + (((float) rand() < remainder * (float)RAND_MAX) ? 1 : 0)); } for (int i=0; icreateParticle(getUseDefaultTemplate()? 0: &getParticleTemplate()); if (P) { _placer->place(P); _shooter->shoot(P); // Now need to transform the position and velocity because we having a moving model. float r = ((float)rand()/(float)RAND_MAX); P->transformPositionVelocity(emitterToPs, prevEmitterToPs, r); //P->transformPositionVelocity(ltw); if (cps) P->setUpTexCoordsAsPartOfConnectedParticleSystem(cps); } else { OSG_NOTICE<<"run out of particle"<numParticlesToCreate(dt); for (int i=0; icreateParticle(getUseDefaultTemplate()? 0: &getParticleTemplate()); if (P) { _placer->place(P); P->setPosition(P->getPosition() * worldToPs); _shooter->shoot(P); P->setVelocity(osg::Matrix::transform3x3(P->getVelocity(), worldToPs)); if (cps) P->setUpTexCoordsAsPartOfConnectedParticleSystem(cps); } } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/DomainOperator.cpp0000644000175000017500000001025513151044751025557 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // Written by Wang Rui, (C) 2010 #include #include #include using namespace osgParticle; void DomainOperator::operate( Particle* P, double dt ) { for ( std::vector::iterator itr=_domains.begin(); itr!=_domains.end(); ++itr ) { switch ( itr->type ) { case Domain::POINT_DOMAIN: handlePoint( *itr, P, dt ); break; case Domain::LINE_DOMAIN: handleLineSegment( *itr, P, dt ); break; case Domain::TRI_DOMAIN: handleTriangle( *itr, P, dt ); break; case Domain::RECT_DOMAIN: handleRectangle( *itr, P, dt ); break; case Domain::PLANE_DOMAIN: handlePlane( *itr, P, dt ); break; case Domain::SPHERE_DOMAIN: handleSphere( *itr, P, dt ); break; case Domain::BOX_DOMAIN: handleBox( *itr, P, dt ); break; case Domain::DISK_DOMAIN: handleDisk( *itr, P, dt ); break; default: break; } } } void DomainOperator::beginOperate( Program* prg ) { if ( prg->getReferenceFrame()==ModularProgram::RELATIVE_RF ) { _backupDomains = _domains; for ( std::vector::iterator itr=_domains.begin(); itr!=_domains.end(); ++itr ) { Domain& domain = *itr; switch ( domain.type ) { case Domain::POINT_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); break; case Domain::LINE_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); domain.v2 = prg->transformLocalToWorld(domain.v2); break; case Domain::TRI_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); domain.v2 = prg->transformLocalToWorld(domain.v2); domain.v3 = prg->transformLocalToWorld(domain.v3); domain.plane.set(domain.v1, domain.v2, domain.v3); computeNewBasis( domain.v2-domain.v1, domain.v3-domain.v1, domain.s1, domain.s2 ); break; case Domain::RECT_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); domain.v2 = prg->rotateLocalToWorld(domain.v2); // Width vector domain.v3 = prg->rotateLocalToWorld(domain.v3); // Height vector domain.plane.set(domain.v1, domain.v1+domain.v2, domain.v1+domain.v3); computeNewBasis( domain.v2, domain.v3, domain.s1, domain.s2 ); break; case Domain::PLANE_DOMAIN: domain.plane.transformProvidingInverse( prg->getLocalToWorldMatrix() ); break; case Domain::SPHERE_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); break; case Domain::BOX_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); domain.v2 = prg->transformLocalToWorld(domain.v2); break; case Domain::DISK_DOMAIN: domain.v1 = prg->transformLocalToWorld(domain.v1); domain.v2 = prg->rotateLocalToWorld(domain.v2); domain.v2.normalize(); // Normal break; default: break; } } } } void DomainOperator::endOperate() { if ( _backupDomains.size()>0 ) { _domains = _backupDomains; _backupDomains.clear(); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ExplosionEffect.cpp0000644000175000017500000001231713151044751025732 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgParticle; ExplosionEffect::ExplosionEffect(bool automaticSetup): ParticleEffect(automaticSetup) { setDefaults(); _position.set(0.0f,0.0f,0.0f); _scale = 1.0f; _intensity = 1.0f; _emitterDuration = 1.0; if (_automaticSetup) buildEffect(); } ExplosionEffect::ExplosionEffect(const osg::Vec3& position, float scale, float intensity) { setDefaults(); _position = position; _scale = scale; _intensity = intensity; _emitterDuration = 1.0; if (_automaticSetup) buildEffect(); } ExplosionEffect::ExplosionEffect(const ExplosionEffect& copy, const osg::CopyOp& copyop): ParticleEffect(copy,copyop) { if (_automaticSetup) buildEffect(); } void ExplosionEffect::setDefaults() { ParticleEffect::setDefaults(); _textureFileName = "Images/smoke.rgb"; _emitterDuration = 1.0; // set up unit particle. _defaultParticleTemplate.setLifeTime(0.5+0.1*_scale); _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 3.0f)); _defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.1f, 1.0f)); _defaultParticleTemplate.setColorRange(osgParticle::rangev4( osg::Vec4(1.0f, 0.8f, 0.2f, 1.0f), osg::Vec4(1.0f, 0.4f, 0.1f, 0.0f))); } void ExplosionEffect::setUpEmitterAndProgram() { // set up particle system if (!_particleSystem) { _particleSystem = new osgParticle::ParticleSystem; } if (_particleSystem.valid()) { _particleSystem->setDefaultAttributes(_textureFileName, false, false); osgParticle::Particle& ptemplate = _particleSystem->getDefaultParticleTemplate(); float radius = 0.4f*_scale; float density = 1.2f; // 1.0kg/m^3 ptemplate.setLifeTime(_defaultParticleTemplate.getLifeTime()); // the following ranges set the envelope of the respective // graphical properties in time. ptemplate.setSizeRange(osgParticle::rangef(radius*_defaultParticleTemplate.getSizeRange().minimum, radius*_defaultParticleTemplate.getSizeRange().maximum)); ptemplate.setAlphaRange(_defaultParticleTemplate.getAlphaRange()); ptemplate.setColorRange(_defaultParticleTemplate.getColorRange()); // these are physical properties of the particle ptemplate.setRadius(radius); ptemplate.setMass(density*radius*radius*radius*osg::PI*4.0f/3.0f); } // set up emitter if (!_emitter) { _emitter = new osgParticle::ModularEmitter; _emitter->setCounter(new osgParticle::RandomRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter); } if (_emitter.valid()) { _emitter->setParticleSystem(_particleSystem.get()); _emitter->setReferenceFrame(_useLocalParticleSystem? osgParticle::ParticleProcessor::ABSOLUTE_RF: osgParticle::ParticleProcessor::RELATIVE_RF); _emitter->setStartTime(_startTime); _emitter->setLifeTime(_emitterDuration); _emitter->setEndless(false); osgParticle::RandomRateCounter* counter = dynamic_cast(_emitter->getCounter()); if (counter) { counter->setRateRange(50*_intensity,100*_intensity); } osgParticle::SectorPlacer* placer = dynamic_cast(_emitter->getPlacer()); if (placer) { placer->setCenter(_position); placer->setRadiusRange(0.0f*_scale,0.25f*_scale); } osgParticle::RadialShooter* shooter = dynamic_cast(_emitter->getShooter()); if (shooter) { shooter->setThetaRange(0.0f, osg::PI_2); shooter->setInitialSpeedRange(1.0f*_scale,10.0f*_scale); } } // set up the program if (!_program) { _program = new osgParticle::FluidProgram; } if (_program.valid()) { _program->setParticleSystem(_particleSystem.get()); _program->setWind(_wind); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ParticleEffect.cpp0000644000175000017500000001053213151044751025512 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osgParticle; ParticleEffect::ParticleEffect(const ParticleEffect& copy, const osg::CopyOp& copyop): osg::Group(copy,copyop), _automaticSetup(copy._automaticSetup), _useLocalParticleSystem(copy._useLocalParticleSystem), _textureFileName(copy._textureFileName), _defaultParticleTemplate(copy._defaultParticleTemplate), _position(copy._position), _scale(copy._scale), _intensity(copy._intensity), _startTime(copy._startTime), _emitterDuration(copy._emitterDuration), _wind(copy._wind) { } void ParticleEffect::setUseLocalParticleSystem(bool local) { if (_useLocalParticleSystem==local) return; _useLocalParticleSystem = local; if (_automaticSetup) buildEffect(); } void ParticleEffect::setTextureFileName(const std::string& filename) { _textureFileName = filename; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setDefaultParticleTemplate(const Particle& p) { _defaultParticleTemplate = p; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setPosition(const osg::Vec3& position) { if (_position==position) return; _position = position; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setScale(float scale) { if (_scale==scale) return; _scale = scale; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setIntensity(float intensity) { if (_intensity==intensity) return; _intensity = intensity; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setStartTime(double startTime) { if (_startTime==startTime) return; _startTime =startTime; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setEmitterDuration(double duration) { if (_emitterDuration==duration) return; _emitterDuration = duration; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setParticleDuration(double duration) { if (_defaultParticleTemplate.getLifeTime()==duration) return; _defaultParticleTemplate.setLifeTime(duration); if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setWind(const osg::Vec3& wind) { if (_wind==wind) return; _wind = wind; if (_automaticSetup) setUpEmitterAndProgram(); } void ParticleEffect::setParticleSystem(ParticleSystem* ps) { if (_particleSystem==ps) return; _particleSystem = ps; if (_automaticSetup) buildEffect(); } void ParticleEffect::setDefaults() { _useLocalParticleSystem = true; _scale = 1.0f; _intensity = 1.0f; _startTime = 0.0; _emitterDuration = 1.0; _wind.set(0.0f,0.0f,0.0f); } void ParticleEffect::buildEffect() { setUpEmitterAndProgram(); osg::ref_ptr emitter = getEmitter(); osg::ref_ptr program = getProgram(); osg::ref_ptr particleSystem = getParticleSystem(); if (!emitter || !particleSystem || !program) return; // clear the children. removeChildren(0,getNumChildren()); // add the emitter addChild(emitter.get()); // add the program to update the particles addChild(program.get()); // add the particle system updater. osg::ref_ptr psu = new osgParticle::ParticleSystemUpdater; psu->addParticleSystem(particleSystem.get()); addChild(psu.get()); if (_useLocalParticleSystem) { particleSystem->setParticleScaleReferenceFrame(ParticleSystem::LOCAL_COORDINATES); // add the geode to the scene graph osg::Geode* geode = new osg::Geode; geode->addDrawable(particleSystem.get()); addChild(geode); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ConnectedParticleSystem.cpp0000644000175000017500000001777213151044751027442 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include using namespace osgParticle; ConnectedParticleSystem::ConnectedParticleSystem(): _lastParticleCreated(Particle::INVALID_INDEX), _maxNumberOfParticlesToSkip(200), _startParticle(Particle::INVALID_INDEX) { } ConnectedParticleSystem::ConnectedParticleSystem(const ConnectedParticleSystem& copy, const osg::CopyOp& copyop): ParticleSystem(copy,copyop), _lastParticleCreated(copy._lastParticleCreated), _maxNumberOfParticlesToSkip(200), _startParticle(copy._startParticle) { } ConnectedParticleSystem::~ConnectedParticleSystem() { } Particle* ConnectedParticleSystem::createParticle(const Particle* ptemplate) { // OSG_NOTICE<setPreviousParticle(_lastParticleCreated); } // set the new particle as the last particle created. _lastParticleCreated = particleIndex; } return particle; } void ConnectedParticleSystem::reuseParticle(int particleIndex) { // OSG_NOTICE<=(int)_particles.size()) return; Particle* particle = &_particles[particleIndex]; int previous = particle->getPreviousParticle(); int next = particle->getNextParticle(); // update start and last entries if (_startParticle == particleIndex) { _startParticle = particle->getNextParticle(); } if (_lastParticleCreated == particleIndex) { _lastParticleCreated = Particle::INVALID_INDEX; } // join up the previous and next particles to account for // the deletion of the this particle if (previous != Particle::INVALID_INDEX) { _particles[previous].setNextParticle(next); } if (next != Particle::INVALID_INDEX) { _particles[next].setPreviousParticle(previous); } // reset the next and previous particle entries of this particle particle->setPreviousParticle(Particle::INVALID_INDEX); particle->setNextParticle(Particle::INVALID_INDEX); // put the particle on the death stack ParticleSystem::reuseParticle(particleIndex); } void ConnectedParticleSystem::drawImplementation(osg::RenderInfo& renderInfo) const { osg::State& state = *renderInfo.getState(); osg::GLBeginEndAdapter& gl = state.getGLBeginEndAdapter(); ScopedReadLock lock(_readWriteMutex); const Particle* particle = (_startParticle != Particle::INVALID_INDEX) ? &_particles[_startParticle] : 0; if (!particle) return; osg::Vec4 pixelSizeVector = osg::CullingSet::computePixelSizeVector(*state.getCurrentViewport(),state.getProjectionMatrix(),state.getModelViewMatrix()); float unitPixelSize = fabs(1.0/(particle->getPosition()*pixelSizeVector)); float pixelSizeOfFirstParticle = unitPixelSize * particle->getCurrentSize(); //float desiredGapBetweenDrawnParticles = 50.0f/unitPixelSize; //float desiredGapBetweenDrawnParticles2 = desiredGapBetweenDrawnParticles*desiredGapBetweenDrawnParticles; float maxPixelError2 = osg::square(1.0f/unitPixelSize); if (pixelSizeOfFirstParticle<1.0) { // draw the connected particles as a line gl.Begin(GL_LINE_STRIP); while(particle != 0) { const osg::Vec4& color = particle->getCurrentColor(); const osg::Vec3& pos = particle->getPosition(); gl.Color4f( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha()); gl.TexCoord2f( particle->getSTexCoord(), 0.5f ); gl.Vertex3fv(pos.ptr()); const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0; if (nextParticle) { const osg::Vec3& nextPos = nextParticle->getPosition(); osg::Vec3 startDelta = nextPos-pos; startDelta.normalize(); float distance2 = 0.0; // now skip particles of required for(unsigned int i=0; i<_maxNumberOfParticlesToSkip && ((distance2getNextParticle()!=Particle::INVALID_INDEX)); ++i) { nextParticle = &_particles[nextParticle->getNextParticle()]; const osg::Vec3& nextPos = nextParticle->getPosition(); osg::Vec3 delta = nextPos-pos; distance2 = (delta^startDelta).length2(); } } particle = nextParticle; } gl.End(); } else { // draw the connected particles as a quad stripped aligned to be orthogonal to the eye osg::Matrix eyeToLocalTransform; eyeToLocalTransform.invert(state.getModelViewMatrix()); osg::Vec3 eyeLocal = osg::Vec3(0.0f,0.0,0.0f)*eyeToLocalTransform; osg::Vec3 delta(0.0f,0.0f,1.0f); gl.Begin(GL_QUAD_STRIP); while(particle != 0) { const osg::Vec4& color = particle->getCurrentColor(); const osg::Vec3& pos = particle->getPosition(); const Particle* nextParticle = (particle->getNextParticle() != Particle::INVALID_INDEX) ? &_particles[particle->getNextParticle()] : 0; if (nextParticle) { const osg::Vec3& nextPos = nextParticle->getPosition(); osg::Vec3 startDelta = nextPos-pos; startDelta.normalize(); float distance2 = 0.0; // now skip particles of required for(unsigned int i=0; i<_maxNumberOfParticlesToSkip && ((distance2getNextParticle()!=Particle::INVALID_INDEX)); ++i) { nextParticle = &_particles[nextParticle->getNextParticle()]; const osg::Vec3& nextPos = nextParticle->getPosition(); delta = nextPos-pos; distance2 = (delta^startDelta).length2(); } delta = nextPos-pos; } osg::Vec3 normal( delta ^ (pos-eyeLocal)); normal.normalize(); normal *= particle->getCurrentSize(); osg::Vec3 bottom(pos-normal); osg::Vec3 top(pos+normal); gl.Color4f( color.r(), color.g(), color.b(), color.a() * particle->getCurrentAlpha()); gl.TexCoord2f( particle->getSTexCoord(), 0.0f ); gl.Vertex3fv(bottom.ptr()); gl.TexCoord2f( particle->getSTexCoord(), 1.0f ); gl.Vertex3fv(top.ptr()); particle = nextParticle; } gl.End(); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/Program.cpp0000644000175000017500000000042513151044751024241 0ustar albertoalberto#include #include #include osgParticle::Program::Program() : ParticleProcessor() { } osgParticle::Program::Program(const Program& copy, const osg::CopyOp& copyop) : ParticleProcessor(copy, copyop) { } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ExplosionDebrisEffect.cpp0000644000175000017500000001250013151044751027055 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include using namespace osgParticle; ExplosionDebrisEffect::ExplosionDebrisEffect(bool automaticSetup): ParticleEffect(automaticSetup) { setDefaults(); _position.set(0.0f,0.0f,0.0f); _scale = 1.0f; _intensity = 1.0f; _emitterDuration = 0.1; _defaultParticleTemplate.setLifeTime(1.0+0.6*_scale); if (_automaticSetup) buildEffect(); } ExplosionDebrisEffect::ExplosionDebrisEffect(const osg::Vec3& position, float scale, float intensity) { setDefaults(); _position = position; _scale = scale; _intensity = intensity; _emitterDuration = 0.1; _defaultParticleTemplate.setLifeTime(1.0+0.6*_scale); if (_automaticSetup) buildEffect(); } ExplosionDebrisEffect::ExplosionDebrisEffect(const ExplosionDebrisEffect& copy, const osg::CopyOp& copyop): ParticleEffect(copy,copyop) { if (_automaticSetup) buildEffect(); } void ExplosionDebrisEffect::setDefaults() { ParticleEffect::setDefaults(); _textureFileName = "Images/particle.rgb"; _emitterDuration = 0.1; // set up unit particle. _defaultParticleTemplate.setLifeTime(1.0+0.6*_scale); _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 3.0f)); _defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.0f, 1.0f)); _defaultParticleTemplate.setColorRange(osgParticle::rangev4( osg::Vec4(0.5f, 0.5f, 0.0f, 1.0f), osg::Vec4(0.2f, 0.2f, 0.2f, 0.5f))); } void ExplosionDebrisEffect::setUpEmitterAndProgram() { // set up particle system if (!_particleSystem) { _particleSystem = new osgParticle::ParticleSystem; } if (_particleSystem.valid()) { _particleSystem->setDefaultAttributes(_textureFileName, false, false); osgParticle::Particle& ptemplate = _particleSystem->getDefaultParticleTemplate(); float radius = 0.05f*_scale; float density = 1000.0f; // 1000.0kg/m^3 ptemplate.setLifeTime(_defaultParticleTemplate.getLifeTime()); // the following ranges set the envelope of the respective // graphical properties in time. ptemplate.setSizeRange(osgParticle::rangef(radius*_defaultParticleTemplate.getSizeRange().minimum, radius*_defaultParticleTemplate.getSizeRange().maximum)); ptemplate.setAlphaRange(_defaultParticleTemplate.getAlphaRange()); ptemplate.setColorRange(_defaultParticleTemplate.getColorRange()); // these are physical properties of the particle ptemplate.setRadius(radius); ptemplate.setMass(density*radius*radius*radius*osg::PI*4.0f/3.0f); } // set up emitter if (!_emitter) { _emitter = new osgParticle::ModularEmitter; _emitter->setCounter(new osgParticle::RandomRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter); } if (_emitter.valid()) { _emitter->setParticleSystem(_particleSystem.get()); _emitter->setReferenceFrame(_useLocalParticleSystem? osgParticle::ParticleProcessor::ABSOLUTE_RF: osgParticle::ParticleProcessor::RELATIVE_RF); _emitter->setStartTime(_startTime); _emitter->setLifeTime(_emitterDuration); _emitter->setEndless(false); osgParticle::RandomRateCounter* counter = dynamic_cast(_emitter->getCounter()); if (counter) { counter->setRateRange(2000*_intensity,2000*_intensity); } osgParticle::SectorPlacer* placer = dynamic_cast(_emitter->getPlacer()); if (placer) { placer->setCenter(_position); placer->setRadiusRange(0.0f*_scale,0.25f*_scale); } osgParticle::RadialShooter* shooter = dynamic_cast(_emitter->getShooter()); if (shooter) { shooter->setThetaRange(0.0f, osg::PI_2); shooter->setInitialSpeedRange(1.0f*_scale,5.0f*_scale); } } // set up program. if (!_program) { _program = new osgParticle::FluidProgram; } if (_program.valid()) { _program->setParticleSystem(_particleSystem.get()); _program->setWind(_wind); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ParticleSystemUpdater.cpp0000644000175000017500000000751313151044751027134 0ustar albertoalberto#include #include #include using namespace osg; osgParticle::ParticleSystemUpdater::ParticleSystemUpdater() : osg::Node(), _t0(-1), _frameNumber(0) { setCullingActive(false); } osgParticle::ParticleSystemUpdater::ParticleSystemUpdater(const ParticleSystemUpdater& copy, const osg::CopyOp& copyop) : osg::Node(copy, copyop), _t0(copy._t0), _frameNumber(0) { ParticleSystem_Vector::const_iterator i; for (i=copy._psv.begin(); i!=copy._psv.end(); ++i) { _psv.push_back(static_cast(copyop(i->get()))); } } void osgParticle::ParticleSystemUpdater::traverse(osg::NodeVisitor& nv) { osgUtil::CullVisitor *cv = dynamic_cast(&nv); if (cv) { if (nv.getFrameStamp()) { if( _frameNumber < nv.getFrameStamp()->getFrameNumber()) { _frameNumber = nv.getFrameStamp()->getFrameNumber(); double t = nv.getFrameStamp()->getSimulationTime(); if (_t0 != -1.0) { ParticleSystem_Vector::iterator i; for (i=_psv.begin(); i!=_psv.end(); ++i) { ParticleSystem* ps = i->get(); ParticleSystem::ScopedWriteLock lock(*(ps->getReadWriteMutex())); // We need to allow at least 2 frames difference, because the particle system's lastFrameNumber // is updated in the draw thread which may not have completed yet. if (!ps->isFrozen() && (!ps->getFreezeOnCull() || ((nv.getFrameStamp()->getFrameNumber()-ps->getLastFrameNumber()) <= 2)) ) { ps->update(t - _t0, nv); } } } _t0 = t; } } else { OSG_WARN << "osgParticle::ParticleSystemUpdater::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n"; } } Node::traverse(nv); } osg::BoundingSphere osgParticle::ParticleSystemUpdater::computeBound() const { return osg::BoundingSphere(); } bool osgParticle::ParticleSystemUpdater::addParticleSystem(ParticleSystem* ps) { _psv.push_back(ps); return true; } bool osgParticle::ParticleSystemUpdater::removeParticleSystem(ParticleSystem* ps) { unsigned int i = getParticleSystemIndex( ps ); if( i >= _psv.size() ) return false; removeParticleSystem( i ); return true; } bool osgParticle::ParticleSystemUpdater::removeParticleSystem(unsigned int pos, unsigned int numParticleSystemsToRemove) { if( (pos < _psv.size()) && (numParticleSystemsToRemove > 0) ) { unsigned int endOfRemoveRange = pos + numParticleSystemsToRemove; if( endOfRemoveRange > _psv.size() ) { OSG_DEBUG<<"Warning: ParticleSystem::removeParticleSystem(i,numParticleSystemsToRemove) has been passed an excessive number"< #include #include #include osgParticle::MultiSegmentPlacer::MultiSegmentPlacer() : Placer(), _total_length(0) { } osgParticle::MultiSegmentPlacer::MultiSegmentPlacer(const MultiSegmentPlacer& copy, const osg::CopyOp& copyop) : Placer(copy, copyop), _vx(copy._vx), _total_length(copy._total_length) { } void osgParticle::MultiSegmentPlacer::recompute_length() { Vertex_vector::iterator i; Vertex_vector::iterator i0 = _vx.begin(); _total_length = 0; for (i=_vx.begin(); i!=_vx.end(); ++i) { _total_length += (i->first - i0->first).length(); i->second = _total_length; i0 = i; } } void osgParticle::MultiSegmentPlacer::place(Particle* P) const { if (_vx.size() >= 2) { float x = rangef(0, _total_length).get_random(); Vertex_vector::const_iterator i; Vertex_vector::const_iterator i0 = _vx.begin(); const Vertex_vector::const_iterator vend = _vx.end(); for (i=_vx.begin(); i!=vend; ++i) { if (x <= i->second) { float t = (x - i0->second) / (i->second - i0->second); P->setPosition(i0->first + (i->first - i0->first) * t); return; } i0 = i; } } else { OSG_WARN << "this MultiSegmentPlacer has less than 2 vertices\n"; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/FluidFrictionOperator.cpp0000644000175000017500000000304113151044751027104 0ustar albertoalberto#include #include #include #include #include osgParticle::FluidFrictionOperator::FluidFrictionOperator(): Operator(), _coeff_A(0), _coeff_B(0), _density(0), _viscosity(0), _ovr_rad(0), _current_program(0) { setFluidToAir(); } osgParticle::FluidFrictionOperator::FluidFrictionOperator(const FluidFrictionOperator& copy, const osg::CopyOp& copyop) : Operator(copy, copyop), _coeff_A(copy._coeff_A), _coeff_B(copy._coeff_B), _density(copy._density), _viscosity(copy._viscosity), _ovr_rad(copy._ovr_rad), _current_program(0) { } void osgParticle::FluidFrictionOperator::operate(Particle* P, double dt) { float r = (_ovr_rad > 0)? _ovr_rad : P->getRadius(); osg::Vec3 v = P->getVelocity()-_wind; float vm = v.normalize(); float R = _coeff_A * r * vm + _coeff_B * r * r * vm * vm; osg::Vec3 Fr(-R * v.x(), -R * v.y(), -R * v.z()); #if 0 // Commenting out rotation of force vector rotation from local to world as the particle velocity itself // should already be in world coords so shouldn't need rotating. if (_current_program->getReferenceFrame() == ModularProgram::RELATIVE_RF) { Fr = _current_program->rotateLocalToWorld(Fr); } #endif // correct unwanted velocity increments osg::Vec3 dv = Fr * P->getMassInv() * dt; float dvl = dv.length(); if (dvl > vm) { dv *= vm / dvl; } P->addVelocity(dv); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/CMakeLists.txt0000644000175000017500000000505313151044751024670 0ustar albertoalberto IF(DYNAMIC_OPENSCENEGRAPH) ADD_DEFINITIONS(-DOSGPARTICLE_LIBRARY) ELSE() ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) ENDIF() SET(LIB_NAME osgParticle) SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) SET(TARGET_H ${HEADER_PATH}/AccelOperator ${HEADER_PATH}/AngularAccelOperator ${HEADER_PATH}/BoxPlacer ${HEADER_PATH}/CenteredPlacer ${HEADER_PATH}/ConnectedParticleSystem ${HEADER_PATH}/ConstantRateCounter ${HEADER_PATH}/Counter ${HEADER_PATH}/Emitter ${HEADER_PATH}/ExplosionDebrisEffect ${HEADER_PATH}/ExplosionEffect ${HEADER_PATH}/Export ${HEADER_PATH}/FireEffect ${HEADER_PATH}/FluidFrictionOperator ${HEADER_PATH}/FluidProgram ${HEADER_PATH}/ForceOperator ${HEADER_PATH}/Interpolator ${HEADER_PATH}/LinearInterpolator ${HEADER_PATH}/ModularEmitter ${HEADER_PATH}/ModularProgram ${HEADER_PATH}/MultiSegmentPlacer ${HEADER_PATH}/Operator ${HEADER_PATH}/Particle ${HEADER_PATH}/ParticleEffect ${HEADER_PATH}/ParticleProcessor ${HEADER_PATH}/ParticleSystem ${HEADER_PATH}/ParticleSystemUpdater ${HEADER_PATH}/Placer ${HEADER_PATH}/PointPlacer ${HEADER_PATH}/PrecipitationEffect ${HEADER_PATH}/Program ${HEADER_PATH}/RadialShooter ${HEADER_PATH}/RandomRateCounter ${HEADER_PATH}/range ${HEADER_PATH}/SectorPlacer ${HEADER_PATH}/SegmentPlacer ${HEADER_PATH}/Shooter ${HEADER_PATH}/SmokeEffect ${HEADER_PATH}/SmokeTrailEffect ${HEADER_PATH}/VariableRateCounter ${HEADER_PATH}/Version ${HEADER_PATH}/CompositePlacer ${HEADER_PATH}/AngularDampingOperator ${HEADER_PATH}/DampingOperator ${HEADER_PATH}/ExplosionOperator ${HEADER_PATH}/OrbitOperator ${HEADER_PATH}/DomainOperator ${HEADER_PATH}/BounceOperator ${HEADER_PATH}/SinkOperator ) # FIXME: For OS X, need flag for Framework or dylib SET(TARGET_SRC ConnectedParticleSystem.cpp Emitter.cpp ExplosionDebrisEffect.cpp ExplosionEffect.cpp FireEffect.cpp FluidFrictionOperator.cpp FluidProgram.cpp ModularEmitter.cpp ModularProgram.cpp MultiSegmentPlacer.cpp Particle.cpp ParticleEffect.cpp ParticleProcessor.cpp ParticleSystem.cpp ParticleSystemUpdater.cpp PrecipitationEffect.cpp Program.cpp SmokeEffect.cpp SmokeTrailEffect.cpp Version.cpp DomainOperator.cpp BounceOperator.cpp SinkOperator.cpp ${OPENSCENEGRAPH_VERSIONINFO_RC} ) SET(TARGET_LIBRARIES osgUtil osgDB osg OpenThreads ) SETUP_LIBRARY(${LIB_NAME}) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ParticleSystem.cpp0000644000175000017500000004466113151044751025614 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USE_LOCAL_SHADERS static double distance(const osg::Vec3& coord, const osg::Matrix& matrix) { // copied from CullVisitor.cpp return -(coord[0]*matrix(0,2)+coord[1]*matrix(1,2)+coord[2]*matrix(2,2)+matrix(3,2)); } osgParticle::ParticleSystem::ParticleSystem() : osg::Drawable(), _def_bbox(osg::Vec3(-10, -10, -10), osg::Vec3(10, 10, 10)), _alignment(BILLBOARD), _align_X_axis(1, 0, 0), _align_Y_axis(0, 1, 0), _particleScaleReferenceFrame(WORLD_COORDINATES), _useVertexArray(false), _useShaders(false), _dirty_uniforms(false), _doublepass(false), _frozen(false), _bmin(0, 0, 0), _bmax(0, 0, 0), _reset_bounds_flag(false), _bounds_computed(false), _def_ptemp(Particle()), _last_frame(0), _dirty_dt(true), _freeze_on_cull(false), _t0(0.0), _dt(0.0), _detail(1), _sortMode(NO_SORT), _visibilityDistance(-1.0), _draw_count(0) { // we don't support display lists because particle systems // are dynamic, and they always changes between frames setSupportsDisplayList(false); } osgParticle::ParticleSystem::ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop) : osg::Drawable(copy, copyop), _def_bbox(copy._def_bbox), _alignment(copy._alignment), _align_X_axis(copy._align_X_axis), _align_Y_axis(copy._align_Y_axis), _particleScaleReferenceFrame(copy._particleScaleReferenceFrame), _useVertexArray(copy._useVertexArray), _useShaders(copy._useShaders), _dirty_uniforms(copy._dirty_uniforms), _doublepass(copy._doublepass), _frozen(copy._frozen), _bmin(copy._bmin), _bmax(copy._bmax), _reset_bounds_flag(copy._reset_bounds_flag), _bounds_computed(copy._bounds_computed), _def_ptemp(copy._def_ptemp), _last_frame(copy._last_frame), _dirty_dt(copy._dirty_dt), _freeze_on_cull(copy._freeze_on_cull), _t0(copy._t0), _dt(copy._dt), _detail(copy._detail), _sortMode(copy._sortMode), _visibilityDistance(copy._visibilityDistance), _draw_count(0) { } osgParticle::ParticleSystem::~ParticleSystem() { } void osgParticle::ParticleSystem::update(double dt, osg::NodeVisitor& nv) { // reset bounds _reset_bounds_flag = true; if (_useShaders) { // Update shader uniforms // This slightly reduces the consumption of traversing the particle vector, because we // don't compute tile and angle attributes that are useleff for shaders. // At present, our lcoal shader implementation will ignore these particle props: // _cur_tile, _s_coord, _t_coord, _prev_pos, _prev_angle and _angle osg::StateSet* stateset = getOrCreateStateSet(); if (_dirty_uniforms) { osg::Uniform* u_vd = stateset->getUniform("visibilityDistance"); if (u_vd) u_vd->set((float)_visibilityDistance); _dirty_uniforms = false; } } for(unsigned int i=0; i<_particles.size(); ++i) { Particle& particle = _particles[i]; if (particle.isAlive()) { if (particle.update(dt, _useShaders)) { update_bounds(particle.getPosition(), particle.getCurrentSize()); } else { reuseParticle(i); } } } if (_sortMode != NO_SORT) { // sort particles osgUtil::CullVisitor* cv = dynamic_cast(&nv); if (cv) { osg::Matrixd modelview = *(cv->getModelViewMatrix()); double scale = (_sortMode==SORT_FRONT_TO_BACK ? -1.0 : 1.0); double deadDistance = DBL_MAX; for (unsigned int i=0; i<_particles.size(); ++i) { Particle& particle = _particles[i]; if (particle.isAlive()) particle.setDepth(distance(particle.getPosition(), modelview) * scale); else particle.setDepth(deadDistance); } std::sort(_particles.begin(), _particles.end()); // Repopulate the death stack as it will have been invalidated by the sort. unsigned int numDead = _deadparts.size(); if (numDead>0) { // clear the death stack _deadparts = Death_stack(); // copy the tail of the _particles vector as this will contain all the dead Particle thanks to the depth sort against DBL_MAX Particle* first_dead_ptr = &_particles[_particles.size()-numDead]; Particle* last_dead_ptr = &_particles[_particles.size()-1]; for(Particle* dead_ptr = first_dead_ptr; dead_ptr<=last_dead_ptr; ++dead_ptr) { _deadparts.push(dead_ptr); } } } } // force recomputing of bounding box on next frame dirtyBound(); } void osgParticle::ParticleSystem::drawImplementation(osg::RenderInfo& renderInfo) const { osg::State& state = *renderInfo.getState(); ScopedReadLock lock(_readWriteMutex); // update the frame count, so other objects can detect when // this particle system is culled _last_frame = state.getFrameStamp()->getFrameNumber(); // update the dirty flag of delta time, so next time a new request for delta time // will automatically cause recomputing _dirty_dt = true; // get the current modelview matrix osg::Matrix modelview = state.getModelViewMatrix(); // set up depth mask for first rendering pass #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) glPushAttrib(GL_DEPTH_BUFFER_BIT); #endif glDepthMask(GL_FALSE); // render, first pass if (_useVertexArray) render_vertex_array(renderInfo); else single_pass_render(renderInfo, modelview); #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) // restore depth mask settings glPopAttrib(); #endif // render, second pass if (_doublepass) { // set up color mask for second rendering pass #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) glPushAttrib(GL_COLOR_BUFFER_BIT); #endif glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // render the particles onto the depth buffer if (_useVertexArray) render_vertex_array(renderInfo); else single_pass_render(renderInfo, modelview); #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) // restore color mask settings glPopAttrib(); #endif } #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) OSG_NOTICE<<"Warning: ParticleSystem::drawImplementation(..) not fully implemented."<setMode(GL_LIGHTING, lighting? osg::StateAttribute::ON: osg::StateAttribute::OFF); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); osg::Material *material = new osg::Material; material->setSpecular(osg::Material::FRONT, osg::Vec4(0, 0, 0, 1)); material->setEmission(osg::Material::FRONT, osg::Vec4(0, 0, 0, 1)); material->setColorMode(lighting? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); if (!texturefile.empty()) { osg::Texture2D *texture = new osg::Texture2D; texture->setImage(osgDB::readRefImageFile(texturefile)); texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::MIRROR); texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::MIRROR); stateset->setTextureAttributeAndModes(texture_unit, texture, osg::StateAttribute::ON); osg::TexEnv *texenv = new osg::TexEnv; texenv->setMode(osg::TexEnv::MODULATE); stateset->setTextureAttribute(texture_unit, texenv); } osg::BlendFunc *blend = new osg::BlendFunc; if (emissive_particles) { blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE); } else { blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); } stateset->setAttributeAndModes(blend, osg::StateAttribute::ON); setStateSet(stateset); setUseVertexArray(false); setUseShaders(false); } void osgParticle::ParticleSystem::setDefaultAttributesUsingShaders(const std::string& texturefile, bool emissive_particles, int texture_unit) { osg::StateSet *stateset = new osg::StateSet; stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); osg::PointSprite *sprite = new osg::PointSprite; stateset->setTextureAttributeAndModes(texture_unit, sprite, osg::StateAttribute::ON); #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) stateset->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON); #else OSG_NOTICE<<"Warning: ParticleSystem::setDefaultAttributesUsingShaders(..) not fully implemented."<setImage(osgDB::readRefImageFile(texturefile)); texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::MIRROR); texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::MIRROR); stateset->setTextureAttributeAndModes(texture_unit, texture, osg::StateAttribute::ON); } osg::BlendFunc *blend = new osg::BlendFunc; if (emissive_particles) { blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE); } else { blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); } stateset->setAttributeAndModes(blend, osg::StateAttribute::ON); osg::Program *program = new osg::Program; #ifdef USE_LOCAL_SHADERS char vertexShaderSource[] = "uniform float visibilityDistance;\n" "varying vec3 basic_prop;\n" "\n" "void main(void)\n" "{\n" " basic_prop = gl_MultiTexCoord0.xyz;\n" " \n" " vec4 ecPos = gl_ModelViewMatrix * gl_Vertex;\n" " float ecDepth = -ecPos.z;\n" " \n" " if (visibilityDistance > 0.0)\n" " {\n" " if (ecDepth <= 0.0 || ecDepth >= visibilityDistance)\n" " basic_prop.x = -1.0;\n" " }\n" " \n" " gl_Position = ftransform();\n" " gl_ClipVertex = ecPos;\n" " \n" " vec4 color = gl_Color;\n" " color.a *= basic_prop.z;\n" " gl_FrontColor = color;\n" " gl_BackColor = gl_FrontColor;\n" "}\n"; char fragmentShaderSource[] = "uniform sampler2D baseTexture;\n" "varying vec3 basic_prop;\n" "\n" "void main(void)\n" "{\n" " if (basic_prop.x < 0.0) discard;\n" " gl_FragColor = gl_Color * texture2D(baseTexture, gl_TexCoord[0].xy);\n" "}\n"; program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); #else program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/particle.vert"))); program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/particle.frag"))); #endif stateset->setAttributeAndModes(program, osg::StateAttribute::ON); stateset->addUniform(new osg::Uniform("visibilityDistance", (float)_visibilityDistance)); stateset->addUniform(new osg::Uniform("baseTexture", texture_unit)); setStateSet(stateset); setUseVertexArray(true); setUseShaders(true); } void osgParticle::ParticleSystem::single_pass_render(osg::RenderInfo& renderInfo, const osg::Matrix& modelview) const { _draw_count = 0; if (_particles.size() <= 0) return; osg::GLBeginEndAdapter* gl = &(renderInfo.getState()->getGLBeginEndAdapter()); float scale = sqrtf(static_cast(_detail)); osg::Vec3 xAxis = _align_X_axis; osg::Vec3 yAxis = _align_Y_axis; osg::Vec3 scaled_aligned_xAxis = _align_X_axis; osg::Vec3 scaled_aligned_yAxis = _align_Y_axis; float xScale = 1.0f; float yScale = 1.0f; if (_alignment==BILLBOARD) { xAxis = osg::Matrix::transform3x3(modelview,_align_X_axis); yAxis = osg::Matrix::transform3x3(modelview,_align_Y_axis); float lengthX2 = xAxis.length2(); float lengthY2 = yAxis.length2(); if (_particleScaleReferenceFrame==LOCAL_COORDINATES) { xScale = 1.0f/sqrtf(lengthX2); yScale = 1.0f/sqrtf(lengthY2); } else { xScale = 1.0f/lengthX2; yScale = 1.0f/lengthY2; } scaled_aligned_xAxis *= xScale; scaled_aligned_yAxis *= yScale; xAxis *= xScale; yAxis *= yScale; } bool requiresEndRender = false; const Particle* startParticle = &_particles[0]; if (startParticle->getShape() != Particle::USER) { startParticle->beginRender(gl); requiresEndRender = true; } else { // Enable writing depth mask when drawing user-defined particles glDepthMask(GL_TRUE); } for(unsigned int i=0; i<_particles.size(); i+=_detail) { const Particle* currentParticle = &_particles[i]; bool insideDistance = true; if (_sortMode != NO_SORT && _visibilityDistance>0.0) insideDistance = (currentParticle->getDepth()>=0.0 && currentParticle->getDepth()<=_visibilityDistance); if (currentParticle->isAlive() && insideDistance) { if (currentParticle->getShape() != startParticle->getShape()) { startParticle->endRender(gl); startParticle = currentParticle; if (currentParticle->getShape() != Particle::USER) { currentParticle->beginRender(gl); requiresEndRender = true; glDepthMask(GL_FALSE); } else glDepthMask(GL_TRUE); } ++_draw_count; if (currentParticle->getShape() == Particle::USER) { if (requiresEndRender) { startParticle->endRender(gl); requiresEndRender = false; } currentParticle->render(renderInfo, currentParticle->getPosition(), currentParticle->getAngle()); continue; } const osg::Vec3& angle = currentParticle->getAngle(); bool requiresRotation = (angle.x()!=0.0f || angle.y()!=0.0f || angle.z()!=0.0f); if (requiresRotation) { osg::Matrix R; R.makeRotate( angle.x(), osg::Vec3(1, 0, 0), angle.y(), osg::Vec3(0, 1, 0), angle.z(), osg::Vec3(0, 0, 1)); if (_alignment==BILLBOARD) { xAxis = osg::Matrix::transform3x3(R,scaled_aligned_xAxis); xAxis = osg::Matrix::transform3x3(modelview,xAxis); yAxis = osg::Matrix::transform3x3(R,scaled_aligned_yAxis); yAxis = osg::Matrix::transform3x3(modelview,yAxis); currentParticle->render(gl,currentParticle->getPosition(), xAxis, yAxis, scale); } else { xAxis = osg::Matrix::transform3x3(R, scaled_aligned_xAxis); yAxis = osg::Matrix::transform3x3(R, scaled_aligned_yAxis); currentParticle->render(gl,currentParticle->getPosition(), xAxis, yAxis, scale); } } else { currentParticle->render(gl,currentParticle->getPosition(), xAxis, yAxis, scale); } } } if (requiresEndRender) startParticle->endRender(gl); } void osgParticle::ParticleSystem::render_vertex_array(osg::RenderInfo& renderInfo) const { if (_particles.size() <= 0) return; // Compute the pointer and offsets Particle_vector::const_iterator itr = _particles.begin(); float* ptr = (float*)(&(*itr)); GLsizei stride = 0; if (_particles.size() > 1) { float* ptr1 = (float*)(&(*(itr+1))); stride = ptr1 - ptr; } GLsizei posOffset = (float*)(&(itr->_position)) - ptr; // Position GLsizei colorOffset = (float*)(&(itr->_current_color)) - ptr; // Color GLsizei velOffset = (float*)(&(itr->_velocity)) - ptr; // Velocity GLsizei propOffset = (float*)(&(itr->_alive)) - ptr; // Alive, size & alpha // Draw particles as arrays osg::State& state = *renderInfo.getState(); state.lazyDisablingOfVertexAttributes(); state.setColorPointer(4, GL_FLOAT, stride * sizeof(float), ptr + colorOffset); state.setVertexPointer(3, GL_FLOAT, stride * sizeof(float), ptr + posOffset); if (_useShaders) { state.setNormalPointer(GL_FLOAT, stride * sizeof(float), ptr + velOffset); state.setTexCoordPointer(0, 3, GL_FLOAT, stride * sizeof(float), ptr + propOffset); } state.applyDisablingOfVertexAttributes(); glDrawArrays(GL_POINTS, 0, _particles.size()); } osg::BoundingBox osgParticle::ParticleSystem::computeBoundingBox() const { if (!_bounds_computed) { return _def_bbox; } else { return osg::BoundingBox(_bmin,_bmax); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/Particle.cpp0000644000175000017500000002127713151044751024405 0ustar albertoalberto#include #include #include #include #include #include #include #include namespace { const float cosPI3 = cosf(osg::PI / 3.0f); const float sinPI3 = sinf(osg::PI / 3.0f); const float hex_texcoord_x1 = 0.5f + 0.5f * cosPI3; const float hex_texcoord_x2 = 0.5f - 0.5f * cosPI3; const float hex_texcoord_y1 = 0.5f + 0.5f * sinPI3; const float hex_texcoord_y2 = 0.5f - 0.5f * sinPI3; } osgParticle::Particle::Particle() : _shape(QUAD), _sr(0.2f, 0.2f), _ar(1, 0), _cr(osg::Vec4(1, 1, 1, 1), osg::Vec4(1, 1, 1, 1)), _si(new LinearInterpolator), _ai(new LinearInterpolator), _ci(new LinearInterpolator), _mustdie(false), _lifeTime(2), _radius(0.2f), _mass(0.1f), _massinv(10.0f), _prev_pos(0, 0, 0), _position(0, 0, 0), _velocity(0, 0, 0), _prev_angle(0, 0, 0), _angle(0, 0, 0), _angul_arvel(0, 0, 0), _t0(0), _alive(1.0f), _current_size(0.0f), _current_alpha(0.0f), _s_tile(1.0f), _t_tile(1.0f), _start_tile(0), _end_tile(0), _cur_tile(-1), _s_coord(0.0f), _t_coord(0.0f), _previousParticle(INVALID_INDEX), _nextParticle(INVALID_INDEX), _depth(0.0) { } bool osgParticle::Particle::update(double dt, bool onlyTimeStamp) { // this method should return false when the particle dies; // so, if we were instructed to die, do it now and return. if (_mustdie) { _alive = -1.0; return false; } double x = 0; // if we don't live forever, compute our normalized age. if (_lifeTime > 0) { x = _t0 / _lifeTime; } _t0 += dt; // if our age is over the lifetime limit, then die and return. if (x > 1) { _alive = -1.0; return false; } // compute the current values for size, alpha and color. if (_lifeTime <= 0) { if (dt == _t0) { _current_size = _sr.get_random(); _current_alpha = _ar.get_random(); _current_color = _cr.get_random(); } } else { _current_size = _si.get()->interpolate(x, _sr); _current_alpha = _ai.get()->interpolate(x, _ar); _current_color = _ci.get()->interpolate(x, _cr); } // update position _prev_pos = _position; _position += _velocity * dt; // return now if we indicate that only time stamp should be updated // the shader will handle remain properties in this case if (onlyTimeStamp) return true; //Compute the current texture tile based on our normalized age int currentTile = _start_tile + static_cast(x * getNumTiles()); //If the current texture tile is different from previous, then compute new texture coords if(currentTile != _cur_tile) { _cur_tile = currentTile; _s_coord = _s_tile * fmod(_cur_tile , 1.0 / _s_tile); _t_coord = 1.0 - _t_tile * (static_cast(_cur_tile * _t_tile) + 1); // OSG_NOTICE< osg::PI*2) _angle.x() -= osg::PI*2; if (_angle.x() < -osg::PI*2) _angle.x() += osg::PI*2; if (_angle.y() > osg::PI*2) _angle.y() -= osg::PI*2; if (_angle.y() < -osg::PI*2) _angle.y() += osg::PI*2; if (_angle.z() > osg::PI*2) _angle.z() -= osg::PI*2; if (_angle.z() < -osg::PI*2) _angle.z() += osg::PI*2; return true; } void osgParticle::Particle::render(osg::GLBeginEndAdapter* gl, const osg::Vec3& xpos, const osg::Vec3& px, const osg::Vec3& py, float scale) const { gl->Color4f( _current_color.x(), _current_color.y(), _current_color.z(), _current_color.w() * _current_alpha); osg::Vec3 p1(px * _current_size * scale); osg::Vec3 p2(py * _current_size * scale); switch (_shape) { case POINT: gl->Vertex3f(xpos.x(), xpos.y(), xpos.z()); break; case QUAD: gl->TexCoord2f(_s_coord, _t_coord); gl->Vertex3fv((xpos-(p1+p2)).ptr()); gl->TexCoord2f(_s_coord+_s_tile, _t_coord); gl->Vertex3fv((xpos+(p1-p2)).ptr()); gl->TexCoord2f(_s_coord+_s_tile, _t_coord+_t_tile); gl->Vertex3fv((xpos+(p1+p2)).ptr()); gl->TexCoord2f(_s_coord, _t_coord+_t_tile); gl->Vertex3fv((xpos-(p1-p2)).ptr()); break; case QUAD_TRIANGLESTRIP: gl->PushMatrix(); gl->Translatef(xpos.x(), xpos.y(), xpos.z()); // we must gl.Begin() and gl.End() here, because each particle is a single strip gl->Begin(GL_TRIANGLE_STRIP); gl->TexCoord2f(_s_coord+_s_tile, _t_coord+_t_tile); gl->Vertex3fv((p1+p2).ptr()); gl->TexCoord2f(_s_coord, _t_coord+_t_tile); gl->Vertex3fv((-p1+p2).ptr()); gl->TexCoord2f(_s_coord+_s_tile, _t_coord); gl->Vertex3fv((p1-p2).ptr()); gl->TexCoord2f(_s_coord, _t_coord); gl->Vertex3fv((-p1-p2).ptr()); gl->End(); gl->PopMatrix(); break; case HEXAGON: gl->PushMatrix(); gl->Translatef(xpos.x(), xpos.y(), xpos.z()); // we must gl.Begin() and gl.End() here, because each particle is a single fan gl->Begin(GL_TRIANGLE_FAN); gl->TexCoord2f(_s_coord + _s_tile * 0.5f, _t_coord + _t_tile * 0.5f); gl->Vertex3f(0,0,0); gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x1, _t_coord + _t_tile * hex_texcoord_y1); gl->Vertex3fv((p1*cosPI3+p2*sinPI3).ptr()); gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x2, _t_coord + _t_tile * hex_texcoord_y1); gl->Vertex3fv((-p1*cosPI3+p2*sinPI3).ptr()); gl->TexCoord2f(_s_coord, _t_coord + _t_tile * 0.5f); gl->Vertex3fv((-p1).ptr()); gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x2, _t_coord + _t_tile * hex_texcoord_y2); gl->Vertex3fv((-p1*cosPI3-p2*sinPI3).ptr()); gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x1, _t_coord + _t_tile * hex_texcoord_y2); gl->Vertex3fv((p1*cosPI3-p2*sinPI3).ptr()); gl->TexCoord2f(_s_coord + _s_tile, _t_coord + _t_tile * 0.5f); gl->Vertex3fv((p1).ptr()); gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x1, _t_coord + _t_tile * hex_texcoord_y1); gl->Vertex3fv((p1*cosPI3+p2*sinPI3).ptr()); gl->End(); gl->PopMatrix(); break; case LINE: { // Get the normalized direction of the particle, to be used in the // calculation of one of the linesegment endpoints. float vl = _velocity.length(); if (vl != 0) { osg::Vec3 v = _velocity * _current_size * scale / vl; gl->TexCoord1f(0); gl->Vertex3f(xpos.x(), xpos.y(), xpos.z()); gl->TexCoord1f(1); gl->Vertex3f(xpos.x() + v.x(), xpos.y() + v.y(), xpos.z() + v.z()); } } break; default: OSG_WARN << "Invalid shape for particles\n"; } } void osgParticle::Particle::render(osg::RenderInfo& renderInfo, const osg::Vec3& xpos, const osg::Vec3& xrot) const { #if defined(OSG_GL_MATRICES_AVAILABLE) if (_drawable.valid()) { bool requiresRotation = (xrot.x()!=0.0f || xrot.y()!=0.0f || xrot.z()!=0.0f); glColor4f(_current_color.x(), _current_color.y(), _current_color.z(), _current_color.w() * _current_alpha); glPushMatrix(); glTranslatef(xpos.x(), xpos.y(), xpos.z()); if (requiresRotation) { osg::Quat rotation(xrot.x(), osg::X_AXIS, xrot.y(), osg::Y_AXIS, xrot.z(), osg::Z_AXIS); #if defined(OSG_GLES1_AVAILABLE) glMultMatrixf(osg::Matrixf(rotation).ptr()); #else glMultMatrixd(osg::Matrixd(rotation).ptr()); #endif } _drawable->draw(renderInfo); glPopMatrix(); } #else OSG_NOTICE<<"Warning: Particle::render(..) not supported for user-defined shape."<getParticle(getPreviousParticle()); const osg::Vec3& previousPosition = previousParticle->getPosition(); const osg::Vec3& newPosition = getPosition(); float distance = (newPosition-previousPosition).length(); float s_coord_delta = 0.5f*distance/getCurrentSize(); float s_coord = previousParticle->_s_coord + s_coord_delta; setTextureTile(1,1,0); _cur_tile = 0; _s_coord = s_coord; _t_coord = 0.0f; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/BounceOperator.cpp0000644000175000017500000001404413151044751025563 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // Written by Wang Rui, (C) 2010 #include #include #include using namespace osgParticle; void BounceOperator::handleTriangle( const Domain& domain, Particle* P, double dt ) { osg::Vec3 nextpos = P->getPosition() + P->getVelocity() * dt; float distance = domain.plane.distance( P->getPosition() ); if ( distance*domain.plane.distance(nextpos)>=0 ) return; osg::Vec3 normal = domain.plane.getNormal(); float nv = normal * P->getVelocity(); osg::Vec3 hitPoint = P->getPosition() - P->getVelocity() * (distance / nv); float upos = (hitPoint - domain.v1) * domain.s1; float vpos = (hitPoint - domain.v1) * domain.s2; if ( upos<0.0f || vpos<0.0f || (upos + vpos)>1.0f ) return; // Compute tangential and normal components of velocity osg::Vec3 vn = normal * nv; osg::Vec3 vt = P->getVelocity() - vn; // Compute new velocity if ( vt.length2()<=_cutoff ) P->setVelocity( vt - vn*_resilience ); else P->setVelocity( vt*(1.0f-_friction) - vn*_resilience ); } void BounceOperator::handleRectangle( const Domain& domain, Particle* P, double dt ) { osg::Vec3 nextpos = P->getPosition() + P->getVelocity() * dt; float distance = domain.plane.distance( P->getPosition() ); if ( distance*domain.plane.distance(nextpos)>=0 ) return; osg::Vec3 normal = domain.plane.getNormal(); float nv = normal * P->getVelocity(); osg::Vec3 hitPoint = P->getPosition() - P->getVelocity() * (distance / nv); float upos = (hitPoint - domain.v1) * domain.s1; float vpos = (hitPoint - domain.v1) * domain.s2; if ( upos<0.0f || upos>1.0f || vpos<0.0f || vpos>1.0f ) return; // Compute tangential and normal components of velocity osg::Vec3 vn = normal * nv; osg::Vec3 vt = P->getVelocity() - vn; // Compute new velocity if ( vt.length2()<=_cutoff ) P->setVelocity( vt - vn*_resilience ); else P->setVelocity( vt*(1.0f-_friction) - vn*_resilience ); } void BounceOperator::handlePlane( const Domain& domain, Particle* P, double dt ) { osg::Vec3 nextpos = P->getPosition() + P->getVelocity() * dt; float distance = domain.plane.distance( P->getPosition() ); if ( distance*domain.plane.distance(nextpos)>=0 ) return; osg::Vec3 normal = domain.plane.getNormal(); float nv = normal * P->getVelocity(); // Compute tangential and normal components of velocity osg::Vec3 vn = normal * nv; osg::Vec3 vt = P->getVelocity() - vn; // Compute new velocity if ( vt.length2()<=_cutoff ) P->setVelocity( vt - vn*_resilience ); else P->setVelocity( vt*(1.0f-_friction) - vn*_resilience ); } void BounceOperator::handleSphere( const Domain& domain, Particle* P, double dt ) { osg::Vec3 nextpos = P->getPosition() + P->getVelocity() * dt; float distance1 = (P->getPosition() - domain.v1).length(); if ( distance1<=domain.r1 ) // Within the sphere { float distance2 = (nextpos - domain.v1).length(); if ( distance2<=domain.r1 ) return; // Bounce back in if going outside osg::Vec3 normal = domain.v1 - P->getPosition(); normal.normalize(); float nmag = P->getVelocity() * normal; // Compute tangential and normal components of velocity osg::Vec3 vn = normal * nmag; osg::Vec3 vt = P->getVelocity() - vn; if ( nmag<0 ) vn = -vn; // Compute new velocity float tanscale = (vt.length2()<=_cutoff) ? 1.0f : (1.0f - _friction); P->setVelocity( vt * tanscale + vn * _resilience ); // Make sure the particle is fixed to stay inside nextpos = P->getPosition() + P->getVelocity() * dt; distance2 = (nextpos - domain.v1).length(); if ( distance2>domain.r1 ) { normal = domain.v1 - nextpos; normal.normalize(); osg::Vec3 wishPoint = domain.v1 - normal * (0.999f * domain.r1); P->setVelocity( (wishPoint - P->getPosition()) / dt ); } } else // Outside the sphere { float distance2 = (nextpos - domain.v1).length(); if ( distance2>domain.r1 ) return; // Bounce back out if going inside osg::Vec3 normal = P->getPosition() - domain.v1; normal.normalize(); float nmag = P->getVelocity() * normal; // Compute tangential and normal components of velocity osg::Vec3 vn = normal * nmag; osg::Vec3 vt = P->getVelocity() - vn; if ( nmag<0 ) vn = -vn; // Compute new velocity float tanscale = (vt.length2()<=_cutoff) ? 1.0f : (1.0f - _friction); P->setVelocity( vt * tanscale + vn * _resilience ); } } void BounceOperator::handleDisk( const Domain& domain, Particle* P, double dt ) { osg::Vec3 nextpos = P->getPosition() + P->getVelocity() * dt; float distance = domain.plane.distance( P->getPosition() ); if ( distance*domain.plane.distance(nextpos)>=0 ) return; osg::Vec3 normal = domain.plane.getNormal(); float nv = normal * P->getVelocity(); osg::Vec3 hitPoint = P->getPosition() - P->getVelocity() * (distance / nv); float radius = (hitPoint - domain.v1).length(); if ( radius>domain.r1 || radiusgetVelocity() - vn; // Compute new velocity if ( vt.length2()<=_cutoff ) P->setVelocity( vt - vn*_resilience ); else P->setVelocity( vt*(1.0f-_friction) - vn*_resilience ); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/ParticleProcessor.cpp0000644000175000017500000001171113151044751026275 0ustar albertoalberto#include #include #include #include #include #include #include using namespace osg; osgParticle::ParticleProcessor::ParticleProcessor() : osg::Node(), _rf(RELATIVE_RF), _enabled(true), _t0(-1), _ps(0), _first_ltw_compute(true), _need_ltw_matrix(false), _first_wtl_compute(true), _need_wtl_matrix(false), _current_nodevisitor(0), _endless(true), _lifeTime(0.0), _startTime(0.0), _currentTime(0.0), _resetTime(0.0), _frameNumber(0) { setCullingActive(false); } osgParticle::ParticleProcessor::ParticleProcessor(const ParticleProcessor& copy, const osg::CopyOp& copyop) : osg::Node(copy, copyop), _rf(copy._rf), _enabled(copy._enabled), _t0(copy._t0), _ps(static_cast(copyop(copy._ps.get()))), _first_ltw_compute(copy._first_ltw_compute), _need_ltw_matrix(copy._need_ltw_matrix), _first_wtl_compute(copy._first_wtl_compute), _need_wtl_matrix(copy._need_wtl_matrix), _current_nodevisitor(0), _endless(copy._endless), _lifeTime(copy._lifeTime), _startTime(copy._startTime), _currentTime(copy._currentTime), _resetTime(copy._resetTime), _frameNumber(copy._frameNumber) { } void osgParticle::ParticleProcessor::traverse(osg::NodeVisitor& nv) { // typecast the NodeVisitor to CullVisitor osgUtil::CullVisitor* cv = dynamic_cast(&nv); // continue only if the visitor actually is a cull visitor if (cv) { // continue only if the particle system is valid if (_ps.valid()) { if (nv.getFrameStamp()) { ParticleSystem::ScopedWriteLock lock(*(_ps->getReadWriteMutex())); //added- 1/17/06- bgandere@nps.edu //a check to make sure we havent updated yet this frame if(_frameNumber < nv.getFrameStamp()->getFrameNumber()) { // retrieve the current time double t = nv.getFrameStamp()->getSimulationTime(); // reset this processor if we've reached the reset point if ((_currentTime >= _resetTime) && (_resetTime > 0)) { _currentTime = 0; _t0 = -1; } // skip if we haven't initialized _t0 yet if (_t0 != -1) { // check whether the processor is alive bool alive = false; if (_currentTime >= _startTime) { if (_endless || (_currentTime < (_startTime + _lifeTime))) alive = true; } // update current time _currentTime += t - _t0; // process only if the particle system is not frozen/culled // We need to allow at least 2 frames difference, because the particle system's lastFrameNumber // is updated in the draw thread which may not have completed yet. if (alive && _enabled && !_ps->isFrozen() && (!_ps->getFreezeOnCull() || ((nv.getFrameStamp()->getFrameNumber()-_ps->getLastFrameNumber()) <= 2)) ) { // initialize matrix flags _need_ltw_matrix = true; _need_wtl_matrix = true; _current_nodevisitor = &nv; // do some process (unimplemented in this base class) process( t - _t0 ); } else { //The values of _previous_wtl_matrix and _previous_ltw_matrix will be invalid //since processing was skipped for this frame _first_ltw_compute = true; _first_wtl_compute = true; } } _t0 = t; } //added- 1/17/06- bgandere@nps.edu //updates the _frameNumber, keeping it current _frameNumber = nv.getFrameStamp()->getFrameNumber(); } else { OSG_WARN << "osgParticle::ParticleProcessor::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n"; } } else { OSG_WARN << "ParticleProcessor \"" << getName() << "\": invalid particle system\n"; } } // call the inherited method Node::traverse(nv); } osg::BoundingSphere osgParticle::ParticleProcessor::computeBound() const { return osg::BoundingSphere(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/Emitter.cpp0000644000175000017500000000055113151044751024243 0ustar albertoalberto#include #include #include osgParticle::Emitter::Emitter() : ParticleProcessor(), _usedeftemp(true) { } osgParticle::Emitter::Emitter(const Emitter& copy, const osg::CopyOp& copyop) : ParticleProcessor(copy, copyop), _usedeftemp(copy._usedeftemp), _ptemp(copy._ptemp) { } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgParticle/FireEffect.cpp0000644000175000017500000001254413151044751024641 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include using namespace osgParticle; FireEffect::FireEffect(bool automaticSetup): ParticleEffect(automaticSetup) { setDefaults(); _position.set(0.0f,0.0f,0.0f); _scale = 1.0f; _intensity = 1.0f; _emitterDuration = 60.0; _defaultParticleTemplate.setLifeTime(0.5+0.1*_scale); if (_automaticSetup) buildEffect(); } FireEffect::FireEffect(const osg::Vec3& position, float scale, float intensity) { setDefaults(); _position = position; _scale = scale; _intensity = intensity; _emitterDuration = 60.0; _defaultParticleTemplate.setLifeTime(0.5+0.1*_scale); if (_automaticSetup) buildEffect(); } FireEffect::FireEffect(const FireEffect& copy, const osg::CopyOp& copyop): ParticleEffect(copy,copyop) { if (_automaticSetup) buildEffect(); } void FireEffect::setDefaults() { ParticleEffect::setDefaults(); _textureFileName = "Images/smoke.rgb"; _emitterDuration = 60.0; // set up unit particle. _defaultParticleTemplate.setLifeTime(0.5+0.1*_scale); _defaultParticleTemplate.setSizeRange(osgParticle::rangef(0.75f, 3.0f)); _defaultParticleTemplate.setAlphaRange(osgParticle::rangef(0.1f, 1.0f)); _defaultParticleTemplate.setColorRange(osgParticle::rangev4( osg::Vec4(1, 0.8f, 0.2f, 1.0f), osg::Vec4(1, 0.3f, 0.2f, 0.0f))); } void FireEffect::setUpEmitterAndProgram() { // set up particle system if (!_particleSystem) { _particleSystem = new osgParticle::ParticleSystem; } if (_particleSystem.valid()) { _particleSystem->setDefaultAttributes(_textureFileName, false, false); osgParticle::Particle& ptemplate = _particleSystem->getDefaultParticleTemplate(); float radius = 0.25f*_scale; float density = 0.5f; // 0.5kg/m^3 ptemplate.setLifeTime(_defaultParticleTemplate.getLifeTime()); // the following ranges set the envelope of the respective // graphical properties in time. ptemplate.setSizeRange(osgParticle::rangef(radius*_defaultParticleTemplate.getSizeRange().minimum, radius*_defaultParticleTemplate.getSizeRange().maximum)); ptemplate.setAlphaRange(_defaultParticleTemplate.getAlphaRange()); ptemplate.setColorRange(_defaultParticleTemplate.getColorRange()); // these are physical properties of the particle // these are physical properties of the particle ptemplate.setRadius(radius); ptemplate.setMass(density*radius*radius*radius*osg::PI*4.0f/3.0f); } // set up emitter if (!_emitter) { _emitter = new osgParticle::ModularEmitter; _emitter->setNumParticlesToCreateMovementCompensationRatio(1.5f); _emitter->setCounter(new osgParticle::RandomRateCounter); _emitter->setPlacer(new osgParticle::SectorPlacer); _emitter->setShooter(new osgParticle::RadialShooter); } if (_emitter.valid()) { _emitter->setParticleSystem(_particleSystem.get()); _emitter->setReferenceFrame(_useLocalParticleSystem? osgParticle::ParticleProcessor::ABSOLUTE_RF: osgParticle::ParticleProcessor::RELATIVE_RF); _emitter->setStartTime(_startTime); _emitter->setLifeTime(_emitterDuration); _emitter->setEndless(false); osgParticle::RandomRateCounter* counter = dynamic_cast(_emitter->getCounter()); if (counter) { counter->setRateRange(10*_intensity,15*_intensity); } osgParticle::SectorPlacer* placer = dynamic_cast(_emitter->getPlacer()); if (placer) { placer->setCenter(_position); placer->setRadiusRange(0.0f*_scale,0.25f*_scale); } osgParticle::RadialShooter* shooter = dynamic_cast(_emitter->getShooter()); if (shooter) { shooter->setThetaRange(0.0f, osg::PI_4); shooter->setInitialSpeedRange(0.0f*_scale,0.0f*_scale); } } // set up program. if (!_program) { _program = new osgParticle::FluidProgram; } if (_program.valid()) { _program->setParticleSystem(_particleSystem.get()); _program->setWind(_wind); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgText/0000755000175000017500000000000013151044751021306 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgText/Text.cpp0000644000175000017500000022461013151044751022743 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include using namespace osg; using namespace osgText; //#define TREES_CODE_FOR_MAKING_SPACES_EDITABLE Text::Text(): _enableDepthWrites(true), _backdropType(NONE), _backdropImplementation(DELAYED_DEPTH_WRITES), _backdropHorizontalOffset(0.07f), _backdropVerticalOffset(0.07f), _backdropColor(0.0f, 0.0f, 0.0f, 1.0f), _colorGradientMode(SOLID), _colorGradientTopLeft(1.0f, 0.0f, 0.0f, 1.0f), _colorGradientBottomLeft(0.0f, 1.0f, 0.0f, 1.0f), _colorGradientBottomRight(0.0f, 0.0f, 1.0f, 1.0f), _colorGradientTopRight(1.0f, 1.0f, 1.0f, 1.0f) { _supportsVertexBufferObjects = true; } Text::Text(const Text& text,const osg::CopyOp& copyop): osgText::TextBase(text,copyop), _enableDepthWrites(text._enableDepthWrites), _backdropType(text._backdropType), _backdropImplementation(text._backdropImplementation), _backdropHorizontalOffset(text._backdropHorizontalOffset), _backdropVerticalOffset(text._backdropVerticalOffset), _backdropColor(text._backdropColor), _colorGradientMode(text._colorGradientMode), _colorGradientTopLeft(text._colorGradientTopLeft), _colorGradientBottomLeft(text._colorGradientBottomLeft), _colorGradientBottomRight(text._colorGradientBottomRight), _colorGradientTopRight(text._colorGradientTopRight) { computeGlyphRepresentation(); } Text::~Text() { } void Text::setFont(osg::ref_ptr font) { if (_font==font) return; osg::StateSet* previousFontStateSet = _font.valid() ? _font->getStateSet() : Font::getDefaultFont()->getStateSet(); osg::StateSet* newFontStateSet = font.valid() ? font->getStateSet() : Font::getDefaultFont()->getStateSet(); if (getStateSet() == previousFontStateSet) { setStateSet( newFontStateSet ); } TextBase::setFont(font); } Font* Text::getActiveFont() { return _font.valid() ? _font.get() : Font::getDefaultFont().get(); } const Font* Text::getActiveFont() const { return _font.valid() ? _font.get() : Font::getDefaultFont().get(); } String::iterator Text::computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last) { Font* activefont = getActiveFont(); if (!activefont) return last; float hr = _characterHeight; float wr = hr/getCharacterAspectRatio(); bool kerning = true; unsigned int previous_charcode = 0; String::iterator lastChar = first; for(bool outOfSpace=false;lastChar!=last;++lastChar) { unsigned int charcode = *lastChar; if (charcode=='\n') { return lastChar; } Glyph* glyph = activefont->getGlyph(_fontSize, charcode); if (glyph) { float width = (float)(glyph->getWidth()) * wr; if (_layout==RIGHT_TO_LEFT) { cursor.x() -= glyph->getHorizontalAdvance() * wr; } // adjust cursor position w.r.t any kerning. if (kerning && previous_charcode) { switch(_layout) { case LEFT_TO_RIGHT: { osg::Vec2 delta(activefont->getKerning(previous_charcode,charcode,_kerningType)); cursor.x() += delta.x() * wr; cursor.y() += delta.y() * hr; break; } case RIGHT_TO_LEFT: { osg::Vec2 delta(activefont->getKerning(charcode,previous_charcode,_kerningType)); cursor.x() -= delta.x() * wr; cursor.y() -= delta.y() * hr; break; } case VERTICAL: break; // no kerning when vertical. } // check to see if we are still within line if not move to next line. } switch(_layout) { case LEFT_TO_RIGHT: { if (_maximumWidth>0.0f && cursor.x()+width>_maximumWidth) outOfSpace=true; if(_maximumHeight>0.0f && cursor.y()<-_maximumHeight) outOfSpace=true; break; } case RIGHT_TO_LEFT: { if (_maximumWidth>0.0f && cursor.x()<-_maximumWidth) outOfSpace=true; if(_maximumHeight>0.0f && cursor.y()<-_maximumHeight) outOfSpace=true; break; } case VERTICAL: if (_maximumHeight>0.0f && cursor.y()<-_maximumHeight) outOfSpace=true; break; } // => word boundary detection & wrapping if (outOfSpace) break; // move the cursor onto the next character. switch(_layout) { case LEFT_TO_RIGHT: cursor.x() += glyph->getHorizontalAdvance() * wr; break; case VERTICAL: cursor.y() -= glyph->getVerticalAdvance() *hr; break; case RIGHT_TO_LEFT: break; // nop. } previous_charcode = charcode; } } // word boundary detection & wrapping if (lastChar!=last) { String::iterator lastValidChar = lastChar; String::iterator prevChar; while (lastValidChar != first){ prevChar = lastValidChar - 1; // last char is after a hyphen if(*lastValidChar == '-') return lastValidChar + 1; // last char is start of whitespace if((*lastValidChar == ' ' || *lastValidChar == '\n') && (*prevChar != ' ' && *prevChar != '\n')) return lastValidChar; // Subtract off glyphs from the cursor position (to correctly center text) if(*prevChar != '-') { Glyph* glyph = activefont->getGlyph(_fontSize, *prevChar); if (glyph) { switch(_layout) { case LEFT_TO_RIGHT: cursor.x() -= glyph->getHorizontalAdvance() * wr; break; case VERTICAL: cursor.y() += glyph->getVerticalAdvance() * hr; break; case RIGHT_TO_LEFT: break; // nop. } } } lastValidChar = prevChar; } } return lastChar; } void Text::computeGlyphRepresentation() { Font* activefont = getActiveFont(); if (!activefont) return; _textureGlyphQuadMap.clear(); _lineCount = 0; if (_text.empty()) { _textBB.set(0,0,0,0,0,0);//no size text TextBase::computePositions(); //to reset the origin return; } //OpenThreads::ScopedLock lock(*(activefont->getSerializeFontCallsMutex())); // initialize bounding box, it will be expanded during glyph position calculation _textBB.init(); osg::Vec2 startOfLine_coords(0.0f,0.0f); osg::Vec2 cursor(startOfLine_coords); osg::Vec2 local(0.0f,0.0f); unsigned int previous_charcode = 0; unsigned int linelength = 0; bool horizontal = _layout!=VERTICAL; bool kerning = true; unsigned int lineNumber = 0; float hr = _characterHeight; float wr = hr/getCharacterAspectRatio(); for(String::iterator itr=_text.begin(); itr!=_text.end(); ) { // record the start of the current line String::iterator startOfLine_itr = itr; // find the end of the current line. osg::Vec2 endOfLine_coords(cursor); String::iterator endOfLine_itr = computeLastCharacterOnLine(endOfLine_coords, itr,_text.end()); linelength = endOfLine_itr - startOfLine_itr; // Set line position to correct alignment. switch(_layout) { case LEFT_TO_RIGHT: { switch(_alignment) { // nothing to be done for these //case LEFT_TOP: //case LEFT_CENTER: //case LEFT_BOTTOM: //case LEFT_BASE_LINE: //case LEFT_BOTTOM_BASE_LINE: // break; case CENTER_TOP: case CENTER_CENTER: case CENTER_BOTTOM: case CENTER_BASE_LINE: case CENTER_BOTTOM_BASE_LINE: cursor.x() = (cursor.x() - endOfLine_coords.x()) * 0.5f; break; case RIGHT_TOP: case RIGHT_CENTER: case RIGHT_BOTTOM: case RIGHT_BASE_LINE: case RIGHT_BOTTOM_BASE_LINE: cursor.x() = cursor.x() - endOfLine_coords.x(); break; default: break; } break; } case RIGHT_TO_LEFT: { switch(_alignment) { case LEFT_TOP: case LEFT_CENTER: case LEFT_BOTTOM: case LEFT_BASE_LINE: case LEFT_BOTTOM_BASE_LINE: cursor.x() = 2*cursor.x() - endOfLine_coords.x(); break; case CENTER_TOP: case CENTER_CENTER: case CENTER_BOTTOM: case CENTER_BASE_LINE: case CENTER_BOTTOM_BASE_LINE: cursor.x() = cursor.x() + (cursor.x() - endOfLine_coords.x()) * 0.5f; break; // nothing to be done for these //case RIGHT_TOP: //case RIGHT_CENTER: //case RIGHT_BOTTOM: //case RIGHT_BASE_LINE: //case RIGHT_BOTTOM_BASE_LINE: // break; default: break; } break; } case VERTICAL: { switch(_alignment) { // TODO: current behaviour top baselines lined up in both cases - need to implement // top of characters alignment - Question is this necessary? // ... otherwise, nothing to be done for these 6 cases //case LEFT_TOP: //case CENTER_TOP: //case RIGHT_TOP: // break; //case LEFT_BASE_LINE: //case CENTER_BASE_LINE: //case RIGHT_BASE_LINE: // break; case LEFT_CENTER: case CENTER_CENTER: case RIGHT_CENTER: cursor.y() = cursor.y() + (cursor.y() - endOfLine_coords.y()) * 0.5f; break; case LEFT_BOTTOM_BASE_LINE: case CENTER_BOTTOM_BASE_LINE: case RIGHT_BOTTOM_BASE_LINE: cursor.y() = cursor.y() - (linelength * _characterHeight); break; case LEFT_BOTTOM: case CENTER_BOTTOM: case RIGHT_BOTTOM: cursor.y() = 2*cursor.y() - endOfLine_coords.y(); break; default: break; } break; } } if (itr!=endOfLine_itr) { for(;itr!=endOfLine_itr;++itr) { unsigned int charcode = *itr; Glyph* glyph = activefont->getGlyph(_fontSize, charcode); if (glyph) { float width = (float)(glyph->getWidth()) * wr; float height = (float)(glyph->getHeight()) * hr; if (_layout==RIGHT_TO_LEFT) { cursor.x() -= glyph->getHorizontalAdvance() * wr; } // adjust cursor position w.r.t any kerning. if (kerning && previous_charcode) { switch(_layout) { case LEFT_TO_RIGHT: { osg::Vec2 delta(activefont->getKerning(previous_charcode,charcode,_kerningType)); cursor.x() += delta.x() * wr; cursor.y() += delta.y() * hr; break; } case RIGHT_TO_LEFT: { osg::Vec2 delta(activefont->getKerning(charcode,previous_charcode,_kerningType)); cursor.x() -= delta.x() * wr; cursor.y() -= delta.y() * hr; break; } case VERTICAL: break; // no kerning when vertical. } } local = cursor; osg::Vec2 bearing(horizontal?glyph->getHorizontalBearing():glyph->getVerticalBearing()); local.x() += bearing.x() * wr; local.y() += bearing.y() * hr; GlyphQuads& glyphquad = _textureGlyphQuadMap[glyph->getTexture()]; glyphquad._glyphs.push_back(glyph); glyphquad._lineNumbers.push_back(lineNumber); // Adjust coordinates and texture coordinates to avoid // clipping the edges of antialiased characters. osg::Vec2 mintc = glyph->getMinTexCoord(); osg::Vec2 maxtc = glyph->getMaxTexCoord(); osg::Vec2 vDiff = maxtc - mintc; float fHorizTCMargin = 1.0f / glyph->getTexture()->getTextureWidth(); float fVertTCMargin = 1.0f / glyph->getTexture()->getTextureHeight(); float fHorizQuadMargin = vDiff.x() == 0.0f ? 0.0f : width * fHorizTCMargin / vDiff.x(); float fVertQuadMargin = vDiff.y() == 0.0f ? 0.0f : height * fVertTCMargin / vDiff.y(); mintc.x() -= fHorizTCMargin; mintc.y() -= fVertTCMargin; maxtc.x() += fHorizTCMargin; maxtc.y() += fVertTCMargin; // set up the coords of the quad osg::Vec2 upLeft = local+osg::Vec2(0.0f-fHorizQuadMargin,height+fVertQuadMargin); osg::Vec2 lowLeft = local+osg::Vec2(0.0f-fHorizQuadMargin,0.0f-fVertQuadMargin); osg::Vec2 lowRight = local+osg::Vec2(width+fHorizQuadMargin,0.0f-fVertQuadMargin); osg::Vec2 upRight = local+osg::Vec2(width+fHorizQuadMargin,height+fVertQuadMargin); glyphquad._coords->push_back(upLeft); glyphquad._coords->push_back(lowLeft); glyphquad._coords->push_back(lowRight); glyphquad._coords->push_back(upRight); // set up the tex coords of the quad glyphquad._texcoords->push_back(osg::Vec2(mintc.x(), maxtc.y())); glyphquad._texcoords->push_back(osg::Vec2(mintc.x(), mintc.y())); glyphquad._texcoords->push_back(osg::Vec2(maxtc.x(), mintc.y())); glyphquad._texcoords->push_back(osg::Vec2(maxtc.x(), maxtc.y())); // move the cursor onto the next character. // also expand bounding box switch(_layout) { case LEFT_TO_RIGHT: cursor.x() += glyph->getHorizontalAdvance() * wr; _textBB.expandBy(osg::Vec3(lowLeft.x(), lowLeft.y(), 0.0f)); //lower left corner _textBB.expandBy(osg::Vec3(upRight.x(), upRight.y(), 0.0f)); //upper right corner break; case VERTICAL: cursor.y() -= glyph->getVerticalAdvance() * hr; _textBB.expandBy(osg::Vec3(upLeft.x(),upLeft.y(),0.0f)); //upper left corner _textBB.expandBy(osg::Vec3(lowRight.x(),lowRight.y(),0.0f)); //lower right corner break; case RIGHT_TO_LEFT: _textBB.expandBy(osg::Vec3(lowRight.x(),lowRight.y(),0.0f)); //lower right corner _textBB.expandBy(osg::Vec3(upLeft.x(),upLeft.y(),0.0f)); //upper left corner break; } previous_charcode = charcode; } } // skip over spaces and return. while (itr != _text.end() && *itr==' ') ++itr; if (itr != _text.end() && *itr=='\n') ++itr; } else { ++itr; } // move to new line. switch(_layout) { case LEFT_TO_RIGHT: { startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing); cursor = startOfLine_coords; previous_charcode = 0; _lineCount++; break; } case RIGHT_TO_LEFT: { startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing); cursor = startOfLine_coords; previous_charcode = 0; _lineCount++; break; } case VERTICAL: { startOfLine_coords.x() += _characterHeight/getCharacterAspectRatio() * (1.0 + _lineSpacing); cursor = startOfLine_coords; previous_charcode = 0; // because _lineCount is the max vertical no. of characters.... _lineCount = (_lineCount >linelength)?_lineCount:linelength; } break; } ++lineNumber; } for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { titr->second.updateQuadIndices(); if (_useVertexBufferObjects) { titr->second.initGPUBufferObjects(); } } TextBase::computePositions(); computeBackdropBoundingBox(); computeBoundingBoxMargin(); computeColorGradients(); } // Returns false if there are no glyphs and the width/height values are invalid. // Also sets avg_width and avg_height to 0.0f if the value is invalid. // This method is used several times in a loop for the same object which will produce the same values. // Further optimization may try saving these values instead of recomputing them. bool Text::computeAverageGlyphWidthAndHeight(float& avg_width, float& avg_height) const { float width = 0.0f; float height = 0.0f; float running_width = 0.0f; float running_height = 0.0f; avg_width = 0.0f; avg_height = 0.0f; int counter = 0; unsigned int i; bool is_valid_size = true; // This section is going to try to compute the average width and height // for a character among the text. The reason I shift by an // average amount per-character instead of shifting each character // by its per-instance amount is because it may look strange to see // the individual backdrop text letters not space themselves the same // way the foreground text does. Using one value gives uniformity. // Note: This loop is repeated for each context. I think it may produce // the same values regardless of context. This code be optimized by moving // this loop outside the loop. for(TextureGlyphQuadMap::const_iterator const_titr=_textureGlyphQuadMap.begin(); const_titr!=_textureGlyphQuadMap.end(); ++const_titr) { const GlyphQuads& glyphquad = const_titr->second; const GlyphQuads::Coords2& coords2 = glyphquad._coords; for (i = 0; i < coords2->size(); i += 4) { width = (*coords2)[i + 2].x() - (*coords2)[i].x(); height = (*coords2)[i].y() - (*coords2)[i + 1].y(); running_width += width; running_height += height; counter++; } } if(0 == counter) { is_valid_size = false; } else { avg_width = running_width/counter; avg_height = running_height/counter; } return is_valid_size; } void Text::computePositions(unsigned int contextID) const { switch(_alignment) { case LEFT_TOP: _offset.set(_textBB.xMin(),_textBB.yMax(),_textBB.zMin()); break; case LEFT_CENTER: _offset.set(_textBB.xMin(),(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break; case LEFT_BOTTOM: _offset.set(_textBB.xMin(),_textBB.yMin(),_textBB.zMin()); break; case CENTER_TOP: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,_textBB.yMax(),_textBB.zMin()); break; case CENTER_CENTER: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break; case CENTER_BOTTOM: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,_textBB.yMin(),_textBB.zMin()); break; case RIGHT_TOP: _offset.set(_textBB.xMax(),_textBB.yMax(),_textBB.zMin()); break; case RIGHT_CENTER: _offset.set(_textBB.xMax(),(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break; case RIGHT_BOTTOM: _offset.set(_textBB.xMax(),_textBB.yMin(),_textBB.zMin()); break; case LEFT_BASE_LINE: _offset.set(0.0f,0.0f,0.0f); break; case CENTER_BASE_LINE: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,0.0f,0.0f); break; case RIGHT_BASE_LINE: _offset.set(_textBB.xMax(),0.0f,0.0f); break; case LEFT_BOTTOM_BASE_LINE: _offset.set(0.0f,-_characterHeight*(1.0 + _lineSpacing)*(_lineCount-1),0.0f); break; case CENTER_BOTTOM_BASE_LINE: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,-_characterHeight*(1.0 + _lineSpacing)*(_lineCount-1),0.0f); break; case RIGHT_BOTTOM_BASE_LINE: _offset.set(_textBB.xMax(),-_characterHeight*(1.0 + _lineSpacing)*(_lineCount-1),0.0f); break; } AutoTransformCache& atc = _autoTransformCache[contextID]; osg::Matrix& matrix = atc._matrix; if (_characterSizeMode!=OBJECT_COORDS || _autoRotateToScreen) { matrix.makeTranslate(-_offset); osg::Matrix rotate_matrix; if (_autoRotateToScreen) { osg::Vec3d trans(atc._modelview.getTrans()); atc._modelview.setTrans(0.0f,0.0f,0.0f); rotate_matrix.invert(atc._modelview); atc._modelview.setTrans(trans); } matrix.postMultRotate(_rotation); if (_characterSizeMode!=OBJECT_COORDS) { osg::Matrix M(rotate_matrix); M.postMultTranslate(_position); M.postMult(atc._modelview); osg::Matrix& P = atc._projection; // compute the pixel size vector. // pre adjust P00,P20,P23,P33 by multiplying them by the viewport window matrix. // here we do it in short hand with the knowledge of how the window matrix is formed // note P23,P33 are multiplied by an implicit 1 which would come from the window matrix. // Robert Osfield, June 2002. // scaling for horizontal pixels float P00 = P(0,0)*atc._width*0.5f; float P20_00 = P(2,0)*atc._width*0.5f + P(2,3)*atc._width*0.5f; osg::Vec3 scale_00(M(0,0)*P00 + M(0,2)*P20_00, M(1,0)*P00 + M(1,2)*P20_00, M(2,0)*P00 + M(2,2)*P20_00); // scaling for vertical pixels float P10 = P(1,1)*atc._height*0.5f; float P20_10 = P(2,1)*atc._height*0.5f + P(2,3)*atc._height*0.5f; osg::Vec3 scale_10(M(0,1)*P10 + M(0,2)*P20_10, M(1,1)*P10 + M(1,2)*P20_10, M(2,1)*P10 + M(2,2)*P20_10); float P23 = P(2,3); float P33 = P(3,3); float pixelSizeVector_w = M(3,2)*P23 + M(3,3)*P33; float pixelSizeVert=(_characterHeight*sqrtf(scale_10.length2()))/(pixelSizeVector_w*0.701f); float pixelSizeHori=(_characterHeight/getCharacterAspectRatio()*sqrtf(scale_00.length2()))/(pixelSizeVector_w*0.701f); // avoid nasty math by preventing a divide by zero if (pixelSizeVert == 0.0f) pixelSizeVert= 1.0f; if (pixelSizeHori == 0.0f) pixelSizeHori= 1.0f; if (_characterSizeMode==SCREEN_COORDS) { float scale_font_vert=_characterHeight/pixelSizeVert; float scale_font_hori=_characterHeight/getCharacterAspectRatio()/pixelSizeHori; if (P10<0) scale_font_vert=-scale_font_vert; matrix.postMultScale(osg::Vec3f(scale_font_hori, scale_font_vert,1.0f)); } else if (pixelSizeVert>getFontHeight()) { float scale_font = getFontHeight()/pixelSizeVert; matrix.postMultScale(osg::Vec3f(scale_font, scale_font,1.0f)); } } if (_autoRotateToScreen) { matrix.postMult(rotate_matrix); } matrix.postMultTranslate(_position); } else if (!_rotation.zeroRotation()) { matrix.makeRotate(_rotation); matrix.preMultTranslate(-_offset); matrix.postMultTranslate(_position); } else { matrix.makeTranslate(_position-_offset); } // now apply matrix to the glyphs. for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { GlyphQuads& glyphquad = titr->second; //OSG_NOTICE<<"Text::computePositions("<getTexEnv()); #endif if (_drawMode & TEXT) { state.disableAllVertexArrays(); // Okay, since ATI's cards/drivers are not working correctly, // we need alternative solutions to glPolygonOffset. // So this is a pick your poison approach. Each alternative // backend has trade-offs associated with it, but with luck, // the user may find that works for them. if(_backdropType != NONE && _backdropImplementation != DELAYED_DEPTH_WRITES) { switch(_backdropImplementation) { case POLYGON_OFFSET: renderWithPolygonOffset(state,colorMultiplier); break; case NO_DEPTH_BUFFER: renderWithNoDepthBuffer(state,colorMultiplier); break; case DEPTH_RANGE: renderWithDepthRange(state,colorMultiplier); break; case STENCIL_BUFFER: renderWithStencilBuffer(state,colorMultiplier); break; default: renderWithPolygonOffset(state,colorMultiplier); } } else { renderWithDelayedDepthWrites(state,colorMultiplier); } // unbind buffers if necessary state.unbindVertexBufferObject(); state.unbindElementBufferObject(); } if (_drawMode & BOUNDINGBOX) { if (_textBB.valid()) { state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF); const osg::Matrix& matrix = _autoTransformCache[contextID]._matrix; osg::Vec3 c00(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix); osg::Vec3 c10(osg::Vec3(_textBB.xMax(),_textBB.yMin(),_textBB.zMin())*matrix); osg::Vec3 c11(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*matrix); osg::Vec3 c01(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*matrix); gl.Color4f(colorMultiplier.r()*_textBBColor.r(),colorMultiplier.g()*_textBBColor.g(),colorMultiplier.b()*_textBBColor.b(),colorMultiplier.a()*_textBBColor.a()); gl.Begin(GL_LINE_LOOP); gl.Vertex3fv(c00.ptr()); gl.Vertex3fv(c10.ptr()); gl.Vertex3fv(c11.ptr()); gl.Vertex3fv(c01.ptr()); gl.End(); } } if (_drawMode & ALIGNMENT) { gl.Color4fv(colorMultiplier.ptr()); float cursorsize = _characterHeight*0.5f; const osg::Matrix& matrix = _autoTransformCache[contextID]._matrix; osg::Vec3 hl(osg::Vec3(_offset.x()-cursorsize,_offset.y(),_offset.z())*matrix); osg::Vec3 hr(osg::Vec3(_offset.x()+cursorsize,_offset.y(),_offset.z())*matrix); osg::Vec3 vt(osg::Vec3(_offset.x(),_offset.y()-cursorsize,_offset.z())*matrix); osg::Vec3 vb(osg::Vec3(_offset.x(),_offset.y()+cursorsize,_offset.z())*matrix); state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF); gl.Begin(GL_LINES); gl.Vertex3fv(hl.ptr()); gl.Vertex3fv(hr.ptr()); gl.Vertex3fv(vt.ptr()); gl.Vertex3fv(vb.ptr()); gl.End(); } } void Text::accept(osg::Drawable::ConstAttributeFunctor& af) const { for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { const GlyphQuads& glyphquad = titr->second; if (!glyphquad._transformedCoords.empty() && glyphquad._transformedCoords[0].valid()) { af.apply(osg::Drawable::VERTICES, glyphquad._transformedCoords[0]->size(), &(glyphquad._transformedCoords[0]->front())); af.apply(osg::Drawable::TEXTURE_COORDS_0, glyphquad._texcoords->size(), &(glyphquad._texcoords->front())); } } } void Text::accept(osg::PrimitiveFunctor& pf) const { for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { const GlyphQuads& glyphquad = titr->second; if (!glyphquad._transformedCoords.empty() && glyphquad._transformedCoords[0].valid()) { pf.setVertexArray(glyphquad._transformedCoords[0]->size(), &(glyphquad._transformedCoords[0]->front())); pf.drawArrays(GL_QUADS, 0, glyphquad._transformedCoords[0]->size()); } } } void Text::setThreadSafeRefUnref(bool threadSafe) { TextBase::setThreadSafeRefUnref(threadSafe); getActiveFont()->setThreadSafeRefUnref(threadSafe); } void Text::resizeGLObjectBuffers(unsigned int maxSize) { TextBase::resizeGLObjectBuffers(maxSize); getActiveFont()->resizeGLObjectBuffers(maxSize); for(TextureGlyphQuadMap::iterator itr = _textureGlyphQuadMap.begin(); itr != _textureGlyphQuadMap.end(); ++itr) { itr->second.resizeGLObjectBuffers(maxSize); } } void Text::releaseGLObjects(osg::State* state) const { TextBase::releaseGLObjects(state); getActiveFont()->releaseGLObjects(state); for(TextureGlyphQuadMap::iterator itr = _textureGlyphQuadMap.begin(); itr != _textureGlyphQuadMap.end(); ++itr) { itr->second.releaseGLObjects(state); } } void Text::setBackdropType(BackdropType type) { if (_backdropType==type) return; _backdropType = type; computeGlyphRepresentation(); } void Text::setBackdropImplementation(BackdropImplementation implementation) { if (_backdropImplementation==implementation) return; _backdropImplementation = implementation; computeGlyphRepresentation(); } void Text::setBackdropOffset(float offset) { _backdropHorizontalOffset = offset; _backdropVerticalOffset = offset; computeGlyphRepresentation(); } void Text::setBackdropOffset(float horizontal, float vertical) { _backdropHorizontalOffset = horizontal; _backdropVerticalOffset = vertical; computeGlyphRepresentation(); } void Text::setBackdropColor(const osg::Vec4& color) { _backdropColor = color; } void Text::setColorGradientMode(ColorGradientMode mode) { if (_colorGradientMode==mode) return; _colorGradientMode = mode; computeGlyphRepresentation(); } void Text::setColorGradientCorners(const osg::Vec4& topLeft, const osg::Vec4& bottomLeft, const osg::Vec4& bottomRight, const osg::Vec4& topRight) { _colorGradientTopLeft = topLeft; _colorGradientBottomLeft = bottomLeft; _colorGradientBottomRight = bottomRight; _colorGradientTopRight = topRight; computeGlyphRepresentation(); } // Formula for f(x,y) from Wikipedia "Bilinear interpolation", 2006-06-18 float Text::bilinearInterpolate(float x1, float x2, float y1, float y2, float x, float y, float q11, float q12, float q21, float q22) const { return ( ((q11 / ((x2-x1)*(y2-y1))) * (x2-x)*(y2-y)) + ((q21 / ((x2-x1)*(y2-y1))) * (x-x1)*(y2-y)) + ((q12 / ((x2-x1)*(y2-y1))) * (x2-x)*(y-y1)) + ((q22 / ((x2-x1)*(y2-y1))) * (x-x1)*(y-y1)) ); } void Text::drawForegroundText(osg::State& state, const GlyphQuads& glyphquad, const osg::Vec4& colorMultiplier) const { unsigned int contextID = state.getContextID(); const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID]; if (transformedCoords.valid() && !transformedCoords->empty()) { state.setVertexPointer(transformedCoords.get()); state.setTexCoordPointer(0, glyphquad._texcoords.get()); if(_colorGradientMode == SOLID) { state.disableColorPointer(); state.Color(colorMultiplier.r()*_color.r(),colorMultiplier.g()*_color.g(),colorMultiplier.b()*_color.b(),colorMultiplier.a()*_color.a()); } else { state.setColorPointer(glyphquad._colorCoords.get()); } glyphquad._quadIndices->draw(state, _useVertexBufferObjects); } } void Text::renderOnlyForegroundText(osg::State& state, const osg::Vec4& colorMultiplier) const { for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { // need to set the texture here... state.applyTextureAttribute(0,titr->first.get()); const GlyphQuads& glyphquad = titr->second; drawForegroundText(state, glyphquad, colorMultiplier); } } void Text::renderWithDelayedDepthWrites(osg::State& state, const osg::Vec4& colorMultiplier) const { // If depth testing is disabled, then just render text as normal if( !state.getLastAppliedMode(GL_DEPTH_TEST) ) { drawTextWithBackdrop(state,colorMultiplier); return; } //glPushAttrib( _enableDepthWrites ? (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) : GL_DEPTH_BUFFER_BIT); // Render to color buffer without writing to depth buffer. glDepthMask(GL_FALSE); drawTextWithBackdrop(state,colorMultiplier); // Render to depth buffer if depth writes requested. if( _enableDepthWrites ) { glDepthMask(GL_TRUE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); drawTextWithBackdrop(state,colorMultiplier); } state.haveAppliedAttribute(osg::StateAttribute::DEPTH); state.haveAppliedAttribute(osg::StateAttribute::COLORMASK); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); //glPopAttrib(); } void Text::drawTextWithBackdrop(osg::State& state, const osg::Vec4& colorMultiplier) const { unsigned int contextID = state.getContextID(); for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { // need to set the texture here... state.applyTextureAttribute(0,titr->first.get()); const GlyphQuads& glyphquad = titr->second; if(_backdropType != NONE) { unsigned int backdrop_index; unsigned int max_backdrop_index; if(_backdropType == OUTLINE) { backdrop_index = 0; max_backdrop_index = 8; } else { backdrop_index = _backdropType; max_backdrop_index = _backdropType+1; } state.setTexCoordPointer(0, glyphquad._texcoords.get()); state.disableColorPointer(); state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); for( ; backdrop_index < max_backdrop_index; backdrop_index++) { const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID]; if (transformedBackdropCoords.valid() && !transformedBackdropCoords->empty()) { state.setVertexPointer(transformedBackdropCoords.get()); glyphquad._quadIndices->draw(state, _useVertexBufferObjects); } } } drawForegroundText(state, glyphquad, colorMultiplier); } } void Text::renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMultiplier) const { #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) unsigned int contextID = state.getContextID(); if (!osg::PolygonOffset::areFactorAndUnitsMultipliersSet()) { osg::PolygonOffset::setFactorAndUnitsMultipliersUsingBestGuessForDriver(); } // Do I really need to do this for glPolygonOffset? glPushAttrib(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_FILL); for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { // need to set the texture here... state.applyTextureAttribute(0,titr->first.get()); const GlyphQuads& glyphquad = titr->second; unsigned int backdrop_index; unsigned int max_backdrop_index; if(_backdropType == OUTLINE) { backdrop_index = 0; max_backdrop_index = 8; } else { backdrop_index = _backdropType; max_backdrop_index = _backdropType+1; } state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords->front())); state.disableColorPointer(); state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); for( ; backdrop_index < max_backdrop_index; backdrop_index++) { const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID]; if (transformedBackdropCoords.valid() && !transformedBackdropCoords->empty()) { state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords->front())); glPolygonOffset(0.1f * osg::PolygonOffset::getFactorMultiplier(), osg::PolygonOffset::getUnitsMultiplier() * (max_backdrop_index-backdrop_index) ); state.drawQuads(0,transformedBackdropCoords->size()); } } // Reset the polygon offset so the foreground text is on top glPolygonOffset(0.0f,0.0f); drawForegroundText(state, glyphquad, colorMultiplier); } glPopAttrib(); #else OSG_NOTICE<<"Warning: Text::renderWithPolygonOffset(..) not implemented."<first.get()); const GlyphQuads& glyphquad = titr->second; unsigned int backdrop_index; unsigned int max_backdrop_index; if(_backdropType == OUTLINE) { backdrop_index = 0; max_backdrop_index = 8; } else { backdrop_index = _backdropType; max_backdrop_index = _backdropType+1; } state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords->front())); state.disableColorPointer(); state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); for( ; backdrop_index < max_backdrop_index; backdrop_index++) { const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID]; if (transformedBackdropCoords.valid() && !transformedBackdropCoords->empty()) { state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords->front())); state.drawQuads(0,transformedBackdropCoords->size()); } } drawForegroundText(state, glyphquad, colorMultiplier); } glPopAttrib(); #else OSG_NOTICE<<"Warning: Text::renderWithNoDepthBuffer(..) not implemented."<first.get()); const GlyphQuads& glyphquad = titr->second; unsigned int backdrop_index; unsigned int max_backdrop_index; if(_backdropType == OUTLINE) { backdrop_index = 0; max_backdrop_index = 8; } else { backdrop_index = _backdropType; max_backdrop_index = _backdropType+1; } state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords->front())); state.disableColorPointer(); state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); for( ; backdrop_index < max_backdrop_index; backdrop_index++) { const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID]; if (transformedBackdropCoords.valid() && !transformedBackdropCoords->empty()) { state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords->front())); double offset = double(max_backdrop_index-backdrop_index)*0.0001; glDepthRange( offset, 1.0+offset); state.drawQuads(0,transformedBackdropCoords->size()); } } glDepthRange(0.0, 1.0); drawForegroundText(state, glyphquad, colorMultiplier); } glPopAttrib(); #else OSG_NOTICE<<"Warning: Text::renderWithDepthRange(..) not implemented."<first.get()); const GlyphQuads& glyphquad = titr->second; unsigned int backdrop_index; unsigned int max_backdrop_index; if(_backdropType == OUTLINE) { backdrop_index = 0; max_backdrop_index = 8; } else { backdrop_index = _backdropType; max_backdrop_index = _backdropType+1; } state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords->front())); state.disableColorPointer(); for( ; backdrop_index < max_backdrop_index; backdrop_index++) { const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID]; if (transformedBackdropCoords.valid() && !transformedBackdropCoords->empty()) { state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords->front())); state.drawQuads(0,transformedBackdropCoords->size()); } } // Draw the foreground text const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID]; if (transformedCoords.valid() && !transformedCoords->empty()) { state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedCoords->front())); state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords->front())); state.drawQuads(0, transformedCoords->size()); } } // disable the depth buffer // glDisable(GL_DEPTH_TEST); // glDepthMask(GL_FALSE); // glDepthMask(GL_TRUE); // glDepthFunc(GL_ALWAYS); // Set the stencil function to pass when the stencil is 1 // Bug: This call seems to have no effect. Try changing to NOTEQUAL // and see the exact same results. glStencilFunc(GL_EQUAL, 1, 1); // disable writing to the stencil buffer glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilMask(GL_FALSE); // Re-enable writing to the color buffer so we can see the results glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Draw all the text again for(titr=_textureGlyphQuadMap.begin(); titr!=_textureGlyphQuadMap.end(); ++titr) { // need to set the texture here... state.applyTextureAttribute(0,titr->first.get()); const GlyphQuads& glyphquad = titr->second; unsigned int backdrop_index; unsigned int max_backdrop_index; if(_backdropType == OUTLINE) { backdrop_index = 0; max_backdrop_index = 8; } else { backdrop_index = _backdropType; max_backdrop_index = _backdropType+1; } state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords->front())); state.disableColorPointer(); state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); for( ; backdrop_index < max_backdrop_index; backdrop_index++) { const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID]; if (transformedBackdropCoords.valid() && !transformedBackdropCoords->empty()) { state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords->front())); state.drawQuads(0,transformedBackdropCoords->size()); } } drawForegroundText(state, glyphquad, colorMultiplier); } glPopAttrib(); #else OSG_NOTICE<<"Warning: Text::renderWithStencilBuffer(..) not implemented."<size(); unsigned int numQuads = numCoords/4; unsigned int numIndices = numQuads*6; if (numCoords % 4 != 0) { OSG_WARN << "size of _coords is not divisible by 4."; } if (numCoords>=16384 && _quadIndices->getType()!=osg::PrimitiveSet::DrawElementsUIntPrimitiveType) { // if we need more indices _quadIndices = new DrawElementsUInt(PrimitiveSet::TRIANGLES); } _quadIndices->resizeElements(numIndices); unsigned int vi=0; for (unsigned int i = 0; i < numCoords; i += 4) { _quadIndices->setElement(vi++, i); _quadIndices->setElement(vi++, i + 1); _quadIndices->setElement(vi++, i + 3); _quadIndices->setElement(vi++, i + 1); _quadIndices->setElement(vi++, i + 2); _quadIndices->setElement(vi++, i + 3); } } void Text::GlyphQuads::initGPUBufferObjects() { osg::VertexBufferObject* vbo = new osg::VertexBufferObject(); _coords->setBinding(osg::Array::BIND_PER_VERTEX); _coords->setVertexBufferObject(vbo); _texcoords->setBinding(osg::Array::BIND_PER_VERTEX); _texcoords->setVertexBufferObject(vbo); _colorCoords->setBinding(osg::Array::BIND_PER_VERTEX); _colorCoords->setVertexBufferObject(vbo); for (size_t i = 0; i < _transformedCoords.size(); i++) { if (_transformedCoords[i].valid()) { _transformedCoords[i]->setBinding(osg::Array::BIND_PER_VERTEX); _transformedCoords[i]->setVertexBufferObject(vbo); } } for (int j = 0; j < 8; j++) { for (size_t i = 0; i < _transformedBackdropCoords[j].size(); i++) { if (_transformedBackdropCoords[j][i].valid()) { _transformedBackdropCoords[j][i]->setBinding(osg::Array::BIND_PER_VERTEX); _transformedBackdropCoords[j][i]->setVertexBufferObject(vbo); } } } _quadIndices->setElementBufferObject(new osg::ElementBufferObject()); } void Text::GlyphQuads::resizeGLObjectBuffers(unsigned int maxSize) { _transformedCoords.resize(maxSize); for (int j = 0; j < 8; j++) { for (size_t i = 0; i < _transformedBackdropCoords[j].size(); i++) { if (_transformedBackdropCoords[j][i].valid()) { _transformedBackdropCoords[j][i]->resizeGLObjectBuffers(maxSize); } } } _quadIndices->resizeGLObjectBuffers(maxSize); initGPUBufferObjects(); } void Text::GlyphQuads::releaseGLObjects(osg::State* state) const { for (int j = 0; j < 8; j++) { for (size_t i = 0; i < _transformedBackdropCoords[j].size(); i++) { if (_transformedBackdropCoords[j][i].valid()) { _transformedBackdropCoords[j][i]->releaseGLObjects(state); } } } _quadIndices->releaseGLObjects(state); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgText/Style.cpp0000644000175000017500000001075013151044751023115 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osgText; ///////////////////////////////////////////////////////////////////////////////////////// // // Bevel // Bevel::Bevel() { _smoothConcaveJunctions = false; _thickness = 0.02f; flatBevel(); } Bevel::Bevel(const Bevel& bevel, const osg::CopyOp& copyop): osg::Object(bevel, copyop), _smoothConcaveJunctions(bevel._smoothConcaveJunctions), _thickness(bevel._thickness), _vertices(bevel._vertices) { } void Bevel::flatBevel(float width) { _vertices.clear(); if (width>0.5f) width = 0.5f; _vertices.push_back(osg::Vec2(0.0f,0.0f)); _vertices.push_back(osg::Vec2(width,1.0f)); if (width<0.5f) _vertices.push_back(osg::Vec2(1-width,1.0f)); _vertices.push_back(osg::Vec2(1.0f,0.0f)); } void Bevel::roundedBevel(float width, unsigned int numSteps) { _vertices.clear(); if (width>0.5f) width = 0.5f; unsigned int i = 0; for(; i<=numSteps; ++i) { float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps)); _vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, sinf(angle)) ); } // start the second half one into the curve if the width is half way across i = width<0.5f ? 0 : 1; for(; i<=numSteps; ++i) { float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps)); _vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, sin(angle)) ); } } void Bevel::roundedBevel2(float width, unsigned int numSteps) { _vertices.clear(); if (width>0.5f) width = 0.5f; float h = 0.1f; float r = 1.0f-h; _vertices.push_back(osg::Vec2(0.0,0.0)); unsigned int i = 0; for(; i<=numSteps; ++i) { float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps)); _vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, h + sinf(angle)*r) ); } // start the second half one into the curve if the width is half way across i = width<0.5f ? 0 : 1; for(; i<=numSteps; ++i) { float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps)); _vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, h + sin(angle)*r) ); } _vertices.push_back(osg::Vec2(1.0,0.0)); } void Bevel::print(std::ostream& /*fout*/) { OSG_NOTICE<<"print bevel"<(copyop(style._bevel.get()))), _widthRatio(style._widthRatio), _thicknessRatio(style._thicknessRatio), _outlineRatio(style._outlineRatio), _sampleDensity(style._sampleDensity) { } /// default Layout implementation used if no other is specified on TextNode osg::ref_ptr

Lua Welcome to Lua 5.2

about · installation · changes · license · reference manual

About Lua

Lua is a powerful, fast, lightweight, embeddable scripting language developed by a team at PUC-Rio, the Pontifical Catholic University of Rio de Janeiro in Brazil. Lua is free software used in many products and projects around the world.

Lua's official web site provides complete information about Lua, including an executive summary and updated documentation, especially the reference manual, which may differ slightly from the local copy distributed in this package.

Installing Lua

Lua is distributed in source form. You need to build it before using it. Building Lua should be straightforward because Lua is implemented in pure ANSI C and compiles unmodified in all known platforms that have an ANSI C compiler. Lua also compiles unmodified as C++. The instructions given below for building Lua are for Unix-like platforms. See also instructions for other systems and customization options.

If you don't have the time or the inclination to compile Lua yourself, get a binary from LuaBinaries. Try also Lua for Windows, an easy-to-use distribution of Lua that includes many useful libraries.

Building Lua

In most Unix-like platforms, simply do "make" with a suitable target. Here are the details.

  1. Open a terminal window and move to the top-level directory, which is named lua-5.2.3. The Makefile there controls both the build process and the installation process.

  2. Do "make" and see if your platform is listed. The platforms currently supported are:

    aix ansi bsd freebsd generic linux macosx mingw posix solaris

    If your platform is listed, just do "make xxx", where xxx is your platform name.

    If your platform is not listed, try the closest one or posix, generic, ansi, in this order.

  3. The compilation takes only a few moments and produces three files in the src directory: lua (the interpreter), luac (the compiler), and liblua.a (the library).

  4. To check that Lua has been built correctly, do "make test" after building Lua. This will run the interpreter and print its version string.

If you're running Linux and get compilation errors, make sure you have installed the readline development package. If you get link errors after that, then try "make linux MYLIBS=-ltermcap".

Installing Lua

Once you have built Lua, you may want to install it in an official place in your system. In this case, do "make install". The official place and the way to install files are defined in the Makefile. You'll probably need the right permissions to install files.

To build and install Lua in one step, do "make xxx install", where xxx is your platform name.

To install Lua locally, do "make local". This will create a directory install with subdirectories bin, include, lib, man, and install Lua as listed below. To install Lua locally, but in some other directory, do "make install INSTALL_TOP=xxx", where xxx is your chosen directory.

bin:
lua luac
include:
lua.h luaconf.h lualib.h lauxlib.h lua.hpp
lib:
liblua.a
man/man1:
lua.1 luac.1

These are the only directories you need for development. If you only want to run Lua programs, you only need the files in bin and man. The files in include and lib are needed for embedding Lua in C or C++ programs.

Customization

Three kinds of things can be customized by editing a file:

  • Where and how to install Lua — edit Makefile.
  • How to build Lua — edit src/Makefile.
  • Lua features — edit src/luaconf.h.

You don't actually need to edit the Makefiles because you may set the relevant variables in the command line when invoking make. Nevertheless, it's probably best to edit and save the Makefiles to record the changes you need.

On the other hand, if you need to customize some Lua features, you'll need to edit src/luaconf.h before building and installing Lua. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. Further customization is available to experts by editing the Lua sources.

We strongly recommend that you enable dynamic loading in src/luaconf.h. This is done automatically for all platforms listed above that have this feature and also for Windows.

Building Lua on other systems

If you're not using the usual Unix tools, then the instructions for building Lua depend on the compiler you use. You'll need to create projects (or whatever your compiler uses) for building the library, the interpreter, and the compiler, as follows:

library:
lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c
interpreter:
library, lua.c
compiler:
library, luac.c

To use Lua as a library in your own programs you'll need to know how to create and use libraries with your compiler. Moreover, to dynamically load C libraries for Lua you'll need to know how to create dynamic libraries and you'll need to make sure that the Lua API functions are accessible to those dynamic libraries — but don't link the Lua library into each dynamic library. For Unix, we recommend that the Lua library be linked statically into the host program and its symbols exported for dynamic linking; src/Makefile does this for the Lua interpreter. For Windows, we recommend that the Lua library be a DLL.

As mentioned above, you may edit src/luaconf.h to customize some features before building Lua.

Changes since Lua 5.1

Here are the main changes introduced in Lua 5.2. The reference manual lists the incompatibilities that had to be introduced.

Main changes

  • yieldable pcall and metamethods
  • new lexical scheme for globals
  • ephemeron tables
  • new library for bitwise operations
  • light C functions
  • emergency garbage collector
  • goto statement
  • finalizers for tables
Here are the other changes introduced in Lua 5.2:

Language

  • no more fenv for threads or functions
  • tables honor the __len metamethod
  • hex and \z escapes in strings
  • support for hexadecimal floats
  • order metamethods work for different types
  • no more verification of opcode consistency
  • hook event "tail return" replaced by "tail call"
  • empty statement
  • break statement may appear in the middle of a block

Libraries

  • arguments for function called through xpcall
  • optional 'mode' argument to load and loadfile (to control binary x text)
  • optional 'env' argument to load and loadfile (environment for loaded chunk)
  • loadlib may load libraries with global names (RTLD_GLOBAL)
  • new function package.searchpath
  • modules receive their paths when loaded
  • optional base in math.log
  • optional separator in string.rep
  • file:write returns file
  • closing a pipe returns exit status
  • os.exit may close state
  • new metamethods __pairs and __ipairs
  • new option 'isrunning' for collectgarbage and lua_gc
  • frontier patterns
  • \0 in patterns
  • new option *L for io.read
  • options for io.lines
  • debug.getlocal can access function varargs

C API

  • main thread predefined in the registry
  • new functions lua_absindex, lua_arith, lua_compare, lua_copy, lua_len, lua_rawgetp, lua_rawsetp, lua_upvalueid, lua_upvaluejoin, lua_version.
  • new functions luaL_checkversion, luaL_setmetatable, luaL_testudata, luaL_tolstring.
  • lua_pushstring and pushlstring return string
  • nparams and isvararg available in debug API
  • new lua_Unsigned

Implementation

  • max constants per function raised to 226
  • generational mode for garbage collection (experimental)
  • NaN trick (experimental)
  • internal (immutable) version of ctypes
  • simpler implementation for string buffers
  • parser uses much less C-stack space (no more auto arrays)

Lua standalone interpreter

  • new -E option to avoid environment variables
  • handling of non-string error messages

License

[osi certified]

Lua is free software distributed under the terms of the MIT license reproduced below; it may be used for any purpose, including commercial purposes, at absolutely no cost without having to ask us. The only requirement is that if you do use Lua, then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. For details, see this.

Copyright © 1994–2013 Lua.org, PUC-Rio.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Last update: Sat Nov 9 22:39:16 BRST 2013 OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/lua.css0000644000175000017500000000272313151044751026054 0ustar albertoalbertohtml { background-color: #F8F8F8 ; } body { border: solid #a0a0a0 1px ; border-radius: 20px ; padding: 26px ; margin: 16px ; color: #000000 ; background-color: #FFFFFF ; font-family: Helvetica, Arial, sans-serif ; text-align: justify ; } h1, h2, h3, h4 { font-family: Verdana, Geneva, sans-serif ; font-weight: normal ; font-style: normal ; } h2 { padding-top: 0.4em ; padding-bottom: 0.4em ; padding-left: 0.8em ; padding-right: 0.8em ; background-color: #D0D0FF ; border-radius: 8px ; border: solid #a0a0a0 1px ; } h3 { padding-left: 0.5em ; border-left: solid #D0D0FF 1em ; } table h3 { padding-left: 0px ; border-left: none ; } a:link { color: #000080 ; background-color: inherit ; text-decoration: none ; } a:visited { background-color: inherit ; text-decoration: none ; } a:link:hover, a:visited:hover { color: #000080 ; background-color: #D0D0FF ; } a:link:active, a:visited:active { color: #FF0000 ; } hr { border: 0 ; height: 1px ; color: #a0a0a0 ; background-color: #a0a0a0 ; display: none ; } table hr { display: block ; } :target { background-color: #F8F8F8 ; padding: 8px ; border: solid #a0a0a0 2px ; border-radius: 8px ; } .footer { color: gray ; font-size: x-small ; } input[type=text] { border: solid #a0a0a0 2px ; border-radius: 2em ; -moz-border-radius: 2em ; background-image: url('images/search.png') ; background-repeat: no-repeat; background-position: 4px center ; padding-left: 20px ; height: 2em ; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/lua.10000644000175000017500000000423413151044751025423 0ustar albertoalberto.\" $Id: lua.man,v 1.13 2011/11/16 17:16:53 lhf Exp $ .TH LUA 1 "$Date: 2011/11/16 17:16:53 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS .B lua [ .I options ] [ .I script [ .I args ] ] .SH DESCRIPTION .B lua is the standalone Lua interpreter. It loads and executes Lua programs, either in textual source form or in precompiled binary form. (Precompiled binaries are output by .BR luac , the Lua compiler.) .B lua can be used as a batch interpreter and also interactively. .LP The given .I options are handled in order and then the Lua program in file .I script is loaded and executed. The given .I args are available to .I script as strings in a global table named .BR arg . If no options or arguments are given, then .B "\-v \-i" is assumed when the standard input is a terminal; otherwise, .B "\-" is assumed. .LP In interactive mode, .B lua prompts the user, reads lines from the standard input, and executes them as they are read. If a line does not contain a complete statement, then a secondary prompt is displayed and lines are read until a complete statement is formed or a syntax error is found. If a line starts with .BR '=' , then .B lua evaluates and displays the values of the expressions in the remainder of the line. .LP At the very start, before even handling the command line, .B lua checks the contents of the environment variables .B LUA_INIT_5_2 or .BR LUA_INIT , in that order. If the contents is of the form .RI '@ filename ', then .I filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed. .SH OPTIONS .TP .BI \-e " stat" execute statement .IR stat . .TP .B \-i enter interactive mode after executing .IR script . .TP .BI \-l " name" execute the equivalent of .IB name =require(' name ') before executing .IR script . .TP .B \-v show version information. .TP .B \-E ignore environment variables. .TP .B \-\- stop handling options. .TP .B \- stop handling options and execute the standard input as a file. .SH "SEE ALSO" .BR luac (1) .br The documentation at lua.org, especially section 7 of the reference manual. .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS R. Ierusalimschy, L. H. de Figueiredo, W. Celes .\" EOF OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/contents.html0000644000175000017500000006066613151044751027316 0ustar albertoalberto Lua 5.2 Reference Manual - contents

Lua 5.2 Reference Manual

The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book Programming in Lua.

start · contents · index


Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the Lua license.

Contents

Index

Lua functions

_G
_VERSION

assert
collectgarbage
dofile
error
getmetatable
ipairs
load
loadfile
next
pairs
pcall
print
rawequal
rawget
rawlen
rawset
require
select
setmetatable
tonumber
tostring
type
xpcall

bit32.arshift
bit32.band
bit32.bnot
bit32.bor
bit32.btest
bit32.bxor
bit32.extract
bit32.lrotate
bit32.lshift
bit32.replace
bit32.rrotate
bit32.rshift

coroutine.create
coroutine.resume
coroutine.running
coroutine.status
coroutine.wrap
coroutine.yield

debug.debug
debug.getuservalue
debug.gethook
debug.getinfo
debug.getlocal
debug.getmetatable
debug.getregistry
debug.getupvalue
debug.setuservalue
debug.sethook
debug.setlocal
debug.setmetatable
debug.setupvalue
debug.traceback
debug.upvalueid
debug.upvaluejoin

file:close
file:flush
file:lines
file:read
file:seek
file:setvbuf
file:write

io.close
io.flush
io.input
io.lines
io.open
io.output
io.popen
io.read
io.stderr
io.stdin
io.stdout
io.tmpfile
io.type
io.write

 

math.abs
math.acos
math.asin
math.atan
math.atan2
math.ceil
math.cos
math.cosh
math.deg
math.exp
math.floor
math.fmod
math.frexp
math.huge
math.ldexp
math.log
math.max
math.min
math.modf
math.pi
math.pow
math.rad
math.random
math.randomseed
math.sin
math.sinh
math.sqrt
math.tan
math.tanh

os.clock
os.date
os.difftime
os.execute
os.exit
os.getenv
os.remove
os.rename
os.setlocale
os.time
os.tmpname

package.config
package.cpath
package.loaded
package.loadlib
package.path
package.preload
package.searchers
package.searchpath

string.byte
string.char
string.dump
string.find
string.format
string.gmatch
string.gsub
string.len
string.lower
string.match
string.rep
string.reverse
string.sub
string.upper

table.concat
table.insert
table.pack
table.remove
table.sort
table.unpack

C API

lua_Alloc
lua_CFunction
lua_Debug
lua_Hook
lua_Integer
lua_Number
lua_Reader
lua_State
lua_Unsigned
lua_Writer

lua_absindex
lua_arith
lua_atpanic
lua_call
lua_callk
lua_checkstack
lua_close
lua_compare
lua_concat
lua_copy
lua_createtable
lua_dump
lua_error
lua_gc
lua_getallocf
lua_getctx
lua_getfield
lua_getglobal
lua_gethook
lua_gethookcount
lua_gethookmask
lua_getinfo
lua_getlocal
lua_getmetatable
lua_getstack
lua_gettable
lua_gettop
lua_getupvalue
lua_getuservalue
lua_insert
lua_isboolean
lua_iscfunction
lua_isfunction
lua_islightuserdata
lua_isnil
lua_isnone
lua_isnoneornil
lua_isnumber
lua_isstring
lua_istable
lua_isthread
lua_isuserdata
lua_len
lua_load
lua_newstate
lua_newtable
lua_newthread
lua_newuserdata
lua_next
lua_pcall
lua_pcallk
lua_pop
lua_pushboolean
lua_pushcclosure
lua_pushcfunction
lua_pushfstring
lua_pushglobaltable
lua_pushinteger
lua_pushlightuserdata
lua_pushliteral
lua_pushlstring
lua_pushnil
lua_pushnumber
lua_pushstring
lua_pushthread
lua_pushunsigned
lua_pushvalue
lua_pushvfstring
lua_rawequal
lua_rawget
lua_rawgeti
lua_rawgetp
lua_rawlen
lua_rawset
lua_rawseti
lua_rawsetp
lua_register
lua_remove
lua_replace
lua_resume
lua_setallocf
lua_setfield
lua_setglobal
lua_sethook
lua_setlocal
lua_setmetatable
lua_settable
lua_settop
lua_setupvalue
lua_setuservalue
lua_status
lua_toboolean
lua_tocfunction
lua_tointeger
lua_tointegerx
lua_tolstring
lua_tonumber
lua_tonumberx
lua_topointer
lua_tostring
lua_tothread
lua_tounsigned
lua_tounsignedx
lua_touserdata
lua_type
lua_typename
lua_upvalueid
lua_upvalueindex
lua_upvaluejoin
lua_version
lua_xmove
lua_yield
lua_yieldk

auxiliary library

luaL_Buffer
luaL_Reg

luaL_addchar
luaL_addlstring
luaL_addsize
luaL_addstring
luaL_addvalue
luaL_argcheck
luaL_argerror
luaL_buffinit
luaL_buffinitsize
luaL_callmeta
luaL_checkany
luaL_checkint
luaL_checkinteger
luaL_checklong
luaL_checklstring
luaL_checknumber
luaL_checkoption
luaL_checkstack
luaL_checkstring
luaL_checktype
luaL_checkudata
luaL_checkunsigned
luaL_checkversion
luaL_dofile
luaL_dostring
luaL_error
luaL_execresult
luaL_fileresult
luaL_getmetafield
luaL_getmetatable
luaL_getsubtable
luaL_gsub
luaL_len
luaL_loadbuffer
luaL_loadbufferx
luaL_loadfile
luaL_loadfilex
luaL_loadstring
luaL_newlib
luaL_newlibtable
luaL_newmetatable
luaL_newstate
luaL_openlibs
luaL_optint
luaL_optinteger
luaL_optlong
luaL_optlstring
luaL_optnumber
luaL_optstring
luaL_optunsigned
luaL_prepbuffer
luaL_prepbuffsize
luaL_pushresult
luaL_pushresultsize
luaL_ref
luaL_requiref
luaL_setfuncs
luaL_setmetatable
luaL_testudata
luaL_tolstring
luaL_traceback
luaL_typename
luaL_unref
luaL_where


Last update: Tue Mar 12 11:22:18 BRT 2013 OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/manual.css0000644000175000017500000000063613151044751026551 0ustar albertoalbertoh3 code { font-family: inherit ; font-size: inherit ; } pre, code { font-size: 12pt ; } span.apii { float: right ; font-family: inherit ; font-style: normal ; font-size: small ; color: gray ; } p+h1, ul+h1 { font-style: normal ; padding-top: 0.4em ; padding-bottom: 0.4em ; padding-left: 16px ; margin-left: -16px ; background-color: #D0D0FF ; border-radius: 8px ; border: solid #000080 1px ; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/manual.html0000644000175000017500000112620113151044751026723 0ustar albertoalberto Lua 5.2 Reference Manual

Lua 5.2 Reference Manual

by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the Lua license.


contents · index

1 – Introduction

Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, lightweight, embeddable scripting language for any program that needs one. Lua is implemented as a library, written in clean C, the common subset of Standard C and C++.

Being an extension language, Lua has no notion of a "main" program: it only works embedded in a host client, called the embedding program or simply the host. The host program can invoke functions to execute a piece of Lua code, can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. The Lua distribution includes a sample host program called lua, which uses the Lua library to offer a complete, standalone Lua interpreter, for interactive or batch use.

Lua is free software, and is provided as usual with no guarantees, as stated in its license. The implementation described in this manual is available at Lua's official web site, www.lua.org.

Like any other reference manual, this document is dry in places. For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, see Roberto's book, Programming in Lua.

2 – Basic Concepts

This section describes the basic concepts of the language.

2.1 – Values and Types

Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.

All values in Lua are first-class values. This means that all values can be stored in variables, passed as arguments to other functions, and returned as results.

There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table. Nil is the type of the value nil, whose main property is to be different from any other value; it usually represents the absence of a useful value. Boolean is the type of the values false and true. Both nil and false make a condition false; any other value makes it true. Number represents real (double-precision floating-point) numbers. Operations on numbers follow the same rules of the underlying C implementation, which, in turn, usually follows the IEEE 754 standard. (It is easy to build Lua interpreters that use other internal representations for numbers, such as single-precision floats or long integers; see file luaconf.h.) String represents immutable sequences of bytes. Lua is 8-bit clean: strings can contain any 8-bit value, including embedded zeros ('\0').

Lua can call (and manipulate) functions written in Lua and functions written in C (see §3.4.9).

The type userdata is provided to allow arbitrary C data to be stored in Lua variables. A userdata value is a pointer to a block of raw memory. There are two kinds of userdata: full userdata, where the block of memory is managed by Lua, and light userdata, where the block of memory is managed by the host. Userdata has no predefined operations in Lua, except assignment and identity test. By using metatables, the programmer can define operations for full userdata values (see §2.4). Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.

The type thread represents independent threads of execution and it is used to implement coroutines (see §2.6). Do not confuse Lua threads with operating-system threads. Lua supports coroutines on all systems, even those that do not support threads.

The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, but with any Lua value except nil and NaN (Not a Number, a special numeric value used to represent undefined or unrepresentable results, such as 0/0). Tables can be heterogeneous; that is, they can contain values of all types (except nil). Any key with value nil is not considered part of the table. Conversely, any key that is not part of a table has an associated value nil.

Tables are the sole data structuring mechanism in Lua; they can be used to represent ordinary arrays, sequences, symbol tables, sets, records, graphs, trees, etc. To represent records, Lua uses the field name as an index. The language supports this representation by providing a.name as syntactic sugar for a["name"]. There are several convenient ways to create tables in Lua (see §3.4.8).

We use the term sequence to denote a table where the set of all positive numeric keys is equal to {1..n} for some integer n, which is called the length of the sequence (see §3.4.6).

Like indices, the values of table fields can be of any type. In particular, because functions are first-class values, table fields can contain functions. Thus tables can also carry methods (see §3.4.10).

The indexing of tables follows the definition of raw equality in the language. The expressions a[i] and a[j] denote the same table element if and only if i and j are raw equal (that is, equal without metamethods).

Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

The library function type returns a string describing the type of a given value (see §6.1).

2.2 – Environments and the Global Environment

As will be discussed in §3.2 and §3.3.3, any reference to a global name var is syntactically translated to _ENV.var. Moreover, every chunk is compiled in the scope of an external local variable called _ENV (see §3.3.2), so _ENV itself is never a global name in a chunk.

Despite the existence of this external _ENV variable and the translation of global names, _ENV is a completely regular name. In particular, you can define new variables and parameters with that name. Each reference to a global name uses the _ENV that is visible at that point in the program, following the usual visibility rules of Lua (see §3.5).

Any table used as the value of _ENV is called an environment.

Lua keeps a distinguished environment called the global environment. This value is kept at a special index in the C registry (see §4.5). In Lua, the variable _G is initialized with this same value.

When Lua compiles a chunk, it initializes the value of its _ENV upvalue with the global environment (see load). Therefore, by default, global variables in Lua code refer to entries in the global environment. Moreover, all standard libraries are loaded in the global environment and several functions there operate on that environment. You can use load (or loadfile) to load a chunk with a different environment. (In C, you have to load the chunk and then change the value of its first upvalue.)

If you change the global environment in the registry (through C code or the debug library), all chunks loaded after the change will get the new environment. Previously loaded chunks are not affected, however, as each has its own reference to the environment in its _ENV variable. Moreover, the variable _G (which is stored in the original global environment) is never updated by Lua.

2.3 – Error Handling

Because Lua is an embedded extension language, all Lua actions start from C code in the host program calling a function from the Lua library (see lua_pcall). Whenever an error occurs during the compilation or execution of a Lua chunk, control returns to the host, which can take appropriate measures (such as printing an error message).

Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, you can use pcall or xpcall to call a given function in protected mode.

Whenever there is an error, an error object (also called an error message) is propagated with information about the error. Lua itself only generates errors where the error object is a string, but programs may generate errors with any value for the error object.

When you use xpcall or lua_pcall, you may give a message handler to be called in case of errors. This function is called with the original error message and returns a new error message. It is called before the error unwinds the stack, so that it can gather more information about the error, for instance by inspecting the stack and creating a stack traceback. This message handler is still protected by the protected call; so, an error inside the message handler will call the message handler again. If this loop goes on, Lua breaks it and returns an appropriate message.

2.4 – Metatables and Metamethods

Every value in Lua can have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" of the value's metatable. If it finds one, Lua calls this function to perform the addition.

The keys in a metatable are derived from the event names; the corresponding values are called metamethods. In the previous example, the event is "add" and the metamethod is the function that performs the addition.

You can query the metatable of any value using the getmetatable function.

You can replace the metatable of tables using the setmetatable function. You cannot change the metatable of other types from Lua (except by using the debug library); you must use the C API for that.

Tables and full userdata have individual metatables (although multiple tables and userdata can share their metatables). Values of all other types share one single metatable per type; that is, there is one single metatable for all numbers, one for all strings, etc. By default, a value has no metatable, but the string library sets a metatable for the string type (see §6.4).

A metatable controls how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. A metatable also can define a function to be called when a userdata or a table is garbage collected. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) controls how Lua will perform the operation.

Metatables control the operations listed next. Each operation is identified by its corresponding name. The key for each operation is a string with its name prefixed by two underscores, '__'; for instance, the key for operation "add" is the string "__add".

The semantics of these operations is better explained by a Lua function describing how the interpreter executes the operation. The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. All functions used in these descriptions (rawget, tonumber, etc.) are described in §6.1. In particular, to retrieve the metamethod of a given object, we use the expression

     metatable(obj)[event]

This should be read as

     rawget(getmetatable(obj) or {}, event)

This means that the access to a metamethod does not invoke other metamethods, and access to objects with no metatables does not fail (it simply results in nil).

For the unary - and # operators, the metamethod is called with a dummy second argument. This extra argument is only to simplify Lua's internals; it may be removed in future versions and therefore it is not present in the following code. (For most uses this extra argument is irrelevant.)

  • "add": the + operation.

    The function getbinhandler below defines how Lua chooses a handler for a binary operation. First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand.

         function getbinhandler (op1, op2, event)
           return metatable(op1)[event] or metatable(op2)[event]
         end
    

    By using this function, the behavior of the op1 + op2 is

         function add_event (op1, op2)
           local o1, o2 = tonumber(op1), tonumber(op2)
           if o1 and o2 then  -- both operands are numeric?
             return o1 + o2   -- '+' here is the primitive 'add'
           else  -- at least one of the operands is not numeric
             local h = getbinhandler(op1, op2, "__add")
             if h then
               -- call the handler with both operands
               return (h(op1, op2))
             else  -- no handler available: default behavior
               error(···)
             end
           end
         end
    

  • "sub": the - operation. Behavior similar to the "add" operation.
  • "mul": the * operation. Behavior similar to the "add" operation.
  • "div": the / operation. Behavior similar to the "add" operation.
  • "mod": the % operation. Behavior similar to the "add" operation, with the operation o1 - floor(o1/o2)*o2 as the primitive operation.
  • "pow": the ^ (exponentiation) operation. Behavior similar to the "add" operation, with the function pow (from the C math library) as the primitive operation.
  • "unm": the unary - operation.
         function unm_event (op)
           local o = tonumber(op)
           if o then  -- operand is numeric?
             return -o  -- '-' here is the primitive 'unm'
           else  -- the operand is not numeric.
             -- Try to get a handler from the operand
             local h = metatable(op).__unm
             if h then
               -- call the handler with the operand
               return (h(op))
             else  -- no handler available: default behavior
               error(···)
             end
           end
         end
    

  • "concat": the .. (concatenation) operation.
         function concat_event (op1, op2)
           if (type(op1) == "string" or type(op1) == "number") and
              (type(op2) == "string" or type(op2) == "number") then
             return op1 .. op2  -- primitive string concatenation
           else
             local h = getbinhandler(op1, op2, "__concat")
             if h then
               return (h(op1, op2))
             else
               error(···)
             end
           end
         end
    

  • "len": the # operation.
         function len_event (op)
           if type(op) == "string" then
             return strlen(op)      -- primitive string length
           else
             local h = metatable(op).__len
             if h then
               return (h(op))       -- call handler with the operand
             elseif type(op) == "table" then
               return #op              -- primitive table length
             else  -- no handler available: error
               error(···)
             end
           end
         end
    

    See §3.4.6 for a description of the length of a table.

  • "eq": the == operation. The function getequalhandler defines how Lua chooses a metamethod for equality. A metamethod is selected only when both values being compared have the same type and the same metamethod for the selected operation, and the values are either tables or full userdata.
         function getequalhandler (op1, op2)
           if type(op1) ~= type(op2) or
              (type(op1) ~= "table" and type(op1) ~= "userdata") then
             return nil     -- different values
           end
           local mm1 = metatable(op1).__eq
           local mm2 = metatable(op2).__eq
           if mm1 == mm2 then return mm1 else return nil end
         end
    

    The "eq" event is defined as follows:

         function eq_event (op1, op2)
           if op1 == op2 then   -- primitive equal?
             return true   -- values are equal
           end
           -- try metamethod
           local h = getequalhandler(op1, op2)
           if h then
             return not not h(op1, op2)
           else
             return false
           end
         end
    

    Note that the result is always a boolean.

  • "lt": the < operation.
         function lt_event (op1, op2)
           if type(op1) == "number" and type(op2) == "number" then
             return op1 < op2   -- numeric comparison
           elseif type(op1) == "string" and type(op2) == "string" then
             return op1 < op2   -- lexicographic comparison
           else
             local h = getbinhandler(op1, op2, "__lt")
             if h then
               return not not h(op1, op2)
             else
               error(···)
             end
           end
         end
    

    Note that the result is always a boolean.

  • "le": the <= operation.
         function le_event (op1, op2)
           if type(op1) == "number" and type(op2) == "number" then
             return op1 <= op2   -- numeric comparison
           elseif type(op1) == "string" and type(op2) == "string" then
             return op1 <= op2   -- lexicographic comparison
           else
             local h = getbinhandler(op1, op2, "__le")
             if h then
               return not not h(op1, op2)
             else
               h = getbinhandler(op1, op2, "__lt")
               if h then
                 return not h(op2, op1)
               else
                 error(···)
               end
             end
           end
         end
    

    Note that, in the absence of a "le" metamethod, Lua tries the "lt", assuming that a <= b is equivalent to not (b < a).

    As with the other comparison operators, the result is always a boolean.

  • "index": The indexing access table[key]. Note that the metamethod is tried only when key is not present in table. (When table is not a table, no key is ever present, so the metamethod is always tried.)
         function gettable_event (table, key)
           local h
           if type(table) == "table" then
             local v = rawget(table, key)
             -- if key is present, return raw value
             if v ~= nil then return v end
             h = metatable(table).__index
             if h == nil then return nil end
           else
             h = metatable(table).__index
             if h == nil then
               error(···)
             end
           end
           if type(h) == "function" then
             return (h(table, key))     -- call the handler
           else return h[key]           -- or repeat operation on it
           end
         end
    

  • "newindex": The indexing assignment table[key] = value. Note that the metamethod is tried only when key is not present in table.
         function settable_event (table, key, value)
           local h
           if type(table) == "table" then
             local v = rawget(table, key)
             -- if key is present, do raw assignment
             if v ~= nil then rawset(table, key, value); return end
             h = metatable(table).__newindex
             if h == nil then rawset(table, key, value); return end
           else
             h = metatable(table).__newindex
             if h == nil then
               error(···)
             end
           end
           if type(h) == "function" then
             h(table, key,value)           -- call the handler
           else h[key] = value             -- or repeat operation on it
           end
         end
    

  • "call": called when Lua calls a value.
         function function_event (func, ...)
           if type(func) == "function" then
             return func(...)   -- primitive call
           else
             local h = metatable(func).__call
             if h then
               return h(func, ...)
             else
               error(···)
             end
           end
         end
    

2.5 – Garbage Collection

Lua performs automatic memory management. This means that you have to worry neither about allocating memory for new objects nor about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector to collect all dead objects (that is, objects that are no longer accessible from Lua). All memory used by Lua is subject to automatic management: strings, tables, userdata, functions, threads, internal structures, etc.

Lua implements an incremental mark-and-sweep collector. It uses two numbers to control its garbage-collection cycles: the garbage-collector pause and the garbage-collector step multiplier. Both use percentage points as units (e.g., a value of 100 means an internal value of 1).

The garbage-collector pause controls how long the collector waits before starting a new cycle. Larger values make the collector less aggressive. Values smaller than 100 mean the collector will not wait to start a new cycle. A value of 200 means that the collector waits for the total memory in use to double before starting a new cycle.

The garbage-collector step multiplier controls the relative speed of the collector relative to memory allocation. Larger values make the collector more aggressive but also increase the size of each incremental step. Values smaller than 100 make the collector too slow and can result in the collector never finishing a cycle. The default is 200, which means that the collector runs at "twice" the speed of memory allocation.

If you set the step multiplier to a very large number (larger than 10% of the maximum number of bytes that the program may use), the collector behaves like a stop-the-world collector. If you then set the pause to 200, the collector behaves as in old Lua versions, doing a complete collection every time Lua doubles its memory usage.

You can change these numbers by calling lua_gc in C or collectgarbage in Lua. You can also use these functions to control the collector directly (e.g., stop and restart it).

As an experimental feature in Lua 5.2, you can change the collector's operation mode from incremental to generational. A generational collector assumes that most objects die young, and therefore it traverses only young (recently created) objects. This behavior can reduce the time used by the collector, but also increases memory usage (as old dead objects may accumulate). To mitigate this second problem, from time to time the generational collector performs a full collection. Remember that this is an experimental feature; you are welcome to try it, but check your gains.

2.5.1 – Garbage-Collection Metamethods

You can set garbage-collector metamethods for tables and, using the C API, for full userdata (see §2.4). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection with external resource management (such as closing files, network or database connections, or freeing your own memory).

For an object (table or userdata) to be finalized when collected, you must mark it for finalization. You mark an object for finalization when you set its metatable and the metatable has a field indexed by the string "__gc". Note that if you set a metatable without a __gc field and later create that field in the metatable, the object will not be marked for finalization. However, after an object is marked, you can freely change the __gc field of its metatable.

When a marked object becomes garbage, it is not collected immediately by the garbage collector. Instead, Lua puts it in a list. After the collection, Lua does the equivalent of the following function for each object in that list:

     function gc_event (obj)
       local h = metatable(obj).__gc
       if type(h) == "function" then
         h(obj)
       end
     end

At the end of each garbage-collection cycle, the finalizers for objects are called in the reverse order that they were marked for collection, among those collected in that cycle; that is, the first finalizer to be called is the one associated with the object marked last in the program. The execution of each finalizer may occur at any point during the execution of the regular code.

Because the object being collected must still be used by the finalizer, it (and other objects accessible only through it) must be resurrected by Lua. Usually, this resurrection is transient, and the object memory is freed in the next garbage-collection cycle. However, if the finalizer stores the object in some global place (e.g., a global variable), then there is a permanent resurrection. In any case, the object memory is freed only when it becomes completely inaccessible; its finalizer will never be called twice.

When you close a state (see lua_close), Lua calls the finalizers of all objects marked for finalization, following the reverse order that they were marked. If any finalizer marks new objects for collection during that phase, these new objects will not be finalized.

2.5.2 – Weak Tables

A weak table is a table whose elements are weak references. A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, then the garbage collector will collect that object.

A weak table can have weak keys, weak values, or both. A table with weak keys allows the collection of its keys, but prevents the collection of its values. A table with both weak keys and weak values allows the collection of both keys and values. In any case, if either the key or the value is collected, the whole pair is removed from the table. The weakness of a table is controlled by the __mode field of its metatable. If the __mode field is a string containing the character 'k', the keys in the table are weak. If __mode contains 'v', the values in the table are weak.

A table with weak keys and strong values is also called an ephemeron table. In an ephemeron table, a value is considered reachable only if its key is reachable. In particular, if the only reference to a key comes through its value, the pair is removed.

Any change in the weakness of a table may take effect only at the next collect cycle. In particular, if you change the weakness to a stronger mode, Lua may still collect some items from that table before the change takes effect.

Only objects that have an explicit construction are removed from weak tables. Values, such as numbers and light C functions, are not subject to garbage collection, and therefore are not removed from weak tables (unless its associated value is collected). Although strings are subject to garbage collection, they do not have an explicit construction, and therefore are not removed from weak tables.

Resurrected objects (that is, objects being finalized and objects accessible only through objects being finalized) have a special behavior in weak tables. They are removed from weak values before running their finalizers, but are removed from weak keys only in the next collection after running their finalizers, when such objects are actually freed. This behavior allows the finalizer to access properties associated with the object through weak tables.

If a weak table is among the resurrected objects in a collection cycle, it may not be properly cleared until the next cycle.

2.6 – Coroutines

Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.

You create a coroutine by calling coroutine.create. Its sole argument is a function that is the main function of the coroutine. The create function only creates a new coroutine and returns a handle to it (an object of type thread); it does not start the coroutine.

You execute a coroutine by calling coroutine.resume. When you first call coroutine.resume, passing as its first argument a thread returned by coroutine.create, the coroutine starts its execution, at the first line of its main function. Extra arguments passed to coroutine.resume are passed on to the coroutine main function. After the coroutine starts running, it runs until it terminates or yields.

A coroutine can terminate its execution in two ways: normally, when its main function returns (explicitly or implicitly, after the last instruction); and abnormally, if there is an unprotected error. In the first case, coroutine.resume returns true, plus any values returned by the coroutine main function. In case of errors, coroutine.resume returns false plus an error message.

A coroutine yields by calling coroutine.yield. When a coroutine yields, the corresponding coroutine.resume returns immediately, even if the yield happens inside nested function calls (that is, not in the main function, but in a function directly or indirectly called by the main function). In the case of a yield, coroutine.resume also returns true, plus any values passed to coroutine.yield. The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield returning any extra arguments passed to coroutine.resume.

Like coroutine.create, the coroutine.wrap function also creates a coroutine, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to this function go as extra arguments to coroutine.resume. coroutine.wrap returns all the values returned by coroutine.resume, except the first one (the boolean error code). Unlike coroutine.resume, coroutine.wrap does not catch errors; any error is propagated to the caller.

As an example of how coroutines work, consider the following code:

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)
     
     print("main", coroutine.resume(co, 1, 10))
     print("main", coroutine.resume(co, "r"))
     print("main", coroutine.resume(co, "x", "y"))
     print("main", coroutine.resume(co, "x", "y"))

When you run it, it produces the following output:

     co-body 1       10
     foo     2
     main    true    4
     co-body r
     main    true    11      -9
     co-body x       y
     main    true    10      end
     main    false   cannot resume dead coroutine

You can also create and manipulate coroutines through the C API: see functions lua_newthread, lua_resume, and lua_yield.

3 – The Language

This section describes the lexis, the syntax, and the semantics of Lua. In other words, this section describes which tokens are valid, how they can be combined, and what their combinations mean.

Language constructs will be explained using the usual extended BNF notation, in which {a} means 0 or more a's, and [a] means an optional a. Non-terminals are shown like non-terminal, keywords are shown like kword, and other terminal symbols are shown like ‘=’. The complete syntax of Lua can be found in §9 at the end of this manual.

3.1 – Lexical Conventions

Lua is a free-form language. It ignores spaces (including new lines) and comments between lexical elements (tokens), except as delimiters between names and keywords.

Names (also called identifiers) in Lua can be any string of letters, digits, and underscores, not beginning with a digit. Identifiers are used to name variables, table fields, and labels.

The following keywords are reserved and cannot be used as names:

     and       break     do        else      elseif    end
     false     for       function  goto      if        in
     local     nil       not       or        repeat    return
     then      true      until     while

Lua is a case-sensitive language: and is a reserved word, but And and AND are two different, valid names. As a convention, names starting with an underscore followed by uppercase letters (such as _VERSION) are reserved for variables used by Lua.

The following strings denote other tokens:

     +     -     *     /     %     ^     #
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]     ::
     ;     :     ,     .     ..    ...

Literal strings can be delimited by matching single or double quotes, and can contain the following C-like escape sequences: '\a' (bell), '\b' (backspace), '\f' (form feed), '\n' (newline), '\r' (carriage return), '\t' (horizontal tab), '\v' (vertical tab), '\\' (backslash), '\"' (quotation mark [double quote]), and '\'' (apostrophe [single quote]). A backslash followed by a real newline results in a newline in the string. The escape sequence '\z' skips the following span of white-space characters, including line breaks; it is particularly useful to break and indent a long literal string into multiple lines without adding the newlines and spaces into the string contents.

A byte in a literal string can also be specified by its numerical value. This can be done with the escape sequence \xXX, where XX is a sequence of exactly two hexadecimal digits, or with the escape sequence \ddd, where ddd is a sequence of up to three decimal digits. (Note that if a decimal escape is to be followed by a digit, it must be expressed using exactly three digits.) Strings in Lua can contain any 8-bit value, including embedded zeros, which can be specified as '\0'.

Literal strings can also be defined using a long format enclosed by long brackets. We define an opening long bracket of level n as an opening square bracket followed by n equal signs followed by another opening square bracket. So, an opening long bracket of level 0 is written as [[, an opening long bracket of level 1 is written as [=[, and so on. A closing long bracket is defined similarly; for instance, a closing long bracket of level 4 is written as ]====]. A long literal starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. It can contain any text except a closing bracket of the proper level. Literals in this bracketed form can run for several lines, do not interpret any escape sequences, and ignore long brackets of any other level. Any kind of end-of-line sequence (carriage return, newline, carriage return followed by newline, or newline followed by carriage return) is converted to a simple newline.

Any byte in a literal string not explicitly affected by the previous rules represents itself. However, Lua opens files for parsing in text mode, and the system file functions may have problems with some control characters. So, it is safer to represent non-text data as a quoted literal with explicit escape sequences for non-text characters.

For convenience, when the opening long bracket is immediately followed by a newline, the newline is not included in the string. As an example, in a system using ASCII (in which 'a' is coded as 97, newline is coded as 10, and '1' is coded as 49), the five literal strings below denote the same string:

     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]

A numerical constant can be written with an optional fractional part and an optional decimal exponent, marked by a letter 'e' or 'E'. Lua also accepts hexadecimal constants, which start with 0x or 0X. Hexadecimal constants also accept an optional fractional part plus an optional binary exponent, marked by a letter 'p' or 'P'. Examples of valid numerical constants are

     3     3.0     3.1416     314.16e-2     0.31416E1
     0xff  0x0.1E  0xA23p-4   0X1.921FB54442D18P+1

A comment starts with a double hyphen (--) anywhere outside a string. If the text immediately after -- is not an opening long bracket, the comment is a short comment, which runs until the end of the line. Otherwise, it is a long comment, which runs until the corresponding closing long bracket. Long comments are frequently used to disable code temporarily.

3.2 – Variables

Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields.

A single name can denote a global variable or a local variable (or a function's formal parameter, which is a particular kind of local variable):

	var ::= Name

Name denotes identifiers, as defined in §3.1.

Any variable name is assumed to be global unless explicitly declared as a local (see §3.3.7). Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope (see §3.5).

Before the first assignment to a variable, its value is nil.

Square brackets are used to index a table:

	var ::= prefixexp ‘[’ exp ‘]

The meaning of accesses to table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to a call gettable_event(t,i). (See §2.4 for a complete description of the gettable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

The syntax var.Name is just syntactic sugar for var["Name"]:

	var ::= prefixexp ‘.’ Name

An access to a global variable x is equivalent to _ENV.x. Due to the way that chunks are compiled, _ENV is never a global name (see §2.2).

3.3 – Statements

Lua supports an almost conventional set of statements, similar to those in Pascal or C. This set includes assignments, control structures, function calls, and variable declarations.

3.3.1 – Blocks

A block is a list of statements, which are executed sequentially:

	block ::= {stat}

Lua has empty statements that allow you to separate statements with semicolons, start a block with a semicolon or write two semicolons in sequence:

	stat ::= ‘;

Function calls and assignments can start with an open parenthesis. This possibility leads to an ambiguity in Lua's grammar. Consider the following fragment:

     a = b + c
     (print or io.write)('done')

The grammar could see it in two ways:

     a = b + c(print or io.write)('done')
     
     a = b + c; (print or io.write)('done')

The current parser always sees such constructions in the first way, interpreting the open parenthesis as the start of the arguments to a call. To avoid this ambiguity, it is a good practice to always precede with a semicolon statements that start with a parenthesis:

     ;(print or io.write)('done')

A block can be explicitly delimited to produce a single statement:

	stat ::= do block end

Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to add a return statement in the middle of another block (see §3.3.4).

3.3.2 – Chunks

The unit of compilation of Lua is called a chunk. Syntactically, a chunk is simply a block:

	chunk ::= block

Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §3.4.10). As such, chunks can define local variables, receive arguments, and return values. Moreover, such anonymous function is compiled as in the scope of an external local variable called _ENV (see §2.2). The resulting function always has _ENV as its only upvalue, even if it does not use that variable.

A chunk can be stored in a file or in a string inside the host program. To execute a chunk, Lua first precompiles the chunk into instructions for a virtual machine, and then it executes the compiled code with an interpreter for the virtual machine.

Chunks can also be precompiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly.

3.3.3 – Assignment

Lua allows multiple assignments. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas:

	stat ::= varlist ‘=’ explist
	varlist ::= var {‘,’ var}
	explist ::= exp {‘,’ exp}

Expressions are discussed in §3.4.

Before the assignment, the list of values is adjusted to the length of the list of variables. If there are more values than needed, the excess values are thrown away. If there are fewer values than needed, the list is extended with as many nil's as needed. If the list of expressions ends with a function call, then all values returned by that call enter the list of values, before the adjustment (except when the call is enclosed in parentheses; see §3.4).

The assignment statement first evaluates all its expressions and only then are the assignments performed. Thus the code

     i = 3
     i, a[i] = i+1, 20

sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) before it is assigned 4. Similarly, the line

     x, y = y, x

exchanges the values of x and y, and

     x, y, z = y, z, x

cyclically permutes the values of x, y, and z.

The meaning of assignments to global variables and table fields can be changed via metatables. An assignment to an indexed variable t[i] = val is equivalent to settable_event(t,i,val). (See §2.4 for a complete description of the settable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

An assignment to a global variable x = val is equivalent to the assignment _ENV.x = val (see §2.2).

3.3.4 – Control Structures

The control structures if, while, and repeat have the usual meaning and familiar syntax:

	stat ::= while exp do block end
	stat ::= repeat block until exp
	stat ::= if exp then block {elseif exp then block} [else block] end

Lua also has a for statement, in two flavors (see §3.3.5).

The condition expression of a control structure can return any value. Both false and nil are considered false. All values different from nil and false are considered true (in particular, the number 0 and the empty string are also true).

In the repeatuntil loop, the inner block does not end at the until keyword, but only after the condition. So, the condition can refer to local variables declared inside the loop block.

The goto statement transfers the program control to a label. For syntactical reasons, labels in Lua are considered statements too:

	stat ::= goto Name
	stat ::= label
	label ::= ‘::’ Name ‘::

A label is visible in the entire block where it is defined, except inside nested blocks where a label with the same name is defined and inside nested functions. A goto may jump to any visible label as long as it does not enter into the scope of a local variable.

Labels and empty statements are called void statements, as they perform no actions.

The break statement terminates the execution of a while, repeat, or for loop, skipping to the next statement after the loop:

	stat ::= break

A break ends the innermost enclosing loop.

The return statement is used to return values from a function or a chunk (which is a function in disguise). Functions can return more than one value, so the syntax for the return statement is

	stat ::= return [explist] [‘;’]

The return statement can only be written as the last statement of a block. If it is really necessary to return in the middle of a block, then an explicit inner block can be used, as in the idiom do return end, because now return is the last statement in its (inner) block.

3.3.5 – For Statement

The for statement has two forms: one numeric and one generic.

The numeric for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax:

	stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end

The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like

     for v = e1, e2, e3 do block end

is equivalent to the code:

     do
       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
       if not (var and limit and step) then error() end
       while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
         local v = var
         block
         var = var + step
       end
     end

Note the following:

  • All three control expressions are evaluated only once, before the loop starts. They must all result in numbers.
  • var, limit, and step are invisible variables. The names shown here are for explanatory purposes only.
  • If the third expression (the step) is absent, then a step of 1 is used.
  • You can use break to exit a for loop.
  • The loop variable v is local to the loop; you cannot use its value after the for ends or is broken. If you need this value, assign it to another variable before breaking or exiting the loop.

The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax:

	stat ::= for namelist in explist do block end
	namelist ::= Name {‘,’ Name}

A for statement like

     for var_1, ···, var_n in explist do block end

is equivalent to the code:

     do
       local f, s, var = explist
       while true do
         local var_1, ···, var_n = f(s, var)
         if var_1 == nil then break end
         var = var_1
         block
       end
     end

Note the following:

  • explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
  • f, s, and var are invisible variables. The names are here for explanatory purposes only.
  • You can use break to exit a for loop.
  • The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.

3.3.6 – Function Calls as Statements

To allow possible side-effects, function calls can be executed as statements:

	stat ::= functioncall

In this case, all returned values are thrown away. Function calls are explained in §3.4.9.

3.3.7 – Local Declarations

Local variables can be declared anywhere inside a block. The declaration can include an initial assignment:

	stat ::= local namelist [‘=’ explist]

If present, an initial assignment has the same semantics of a multiple assignment (see §3.3.3). Otherwise, all variables are initialized with nil.

A chunk is also a block (see §3.3.2), and so local variables can be declared in a chunk outside any explicit block.

The visibility rules for local variables are explained in §3.5.

3.4 – Expressions

The basic expressions in Lua are the following:

	exp ::= prefixexp
	exp ::= nil | false | true
	exp ::= Number
	exp ::= String
	exp ::= functiondef
	exp ::= tableconstructor
	exp ::= ‘...’
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | ‘(’ exp ‘)

Numbers and literal strings are explained in §3.1; variables are explained in §3.2; function definitions are explained in §3.4.10; function calls are explained in §3.4.9; table constructors are explained in §3.4.8. Vararg expressions, denoted by three dots ('...'), can only be used when directly inside a vararg function; they are explained in §3.4.10.

Binary operators comprise arithmetic operators (see §3.4.1), relational operators (see §3.4.3), logical operators (see §3.4.4), and the concatenation operator (see §3.4.5). Unary operators comprise the unary minus (see §3.4.1), the unary not (see §3.4.4), and the unary length operator (see §3.4.6).

Both function calls and vararg expressions can result in multiple values. If a function call is used as a statement (see §3.3.6), then its return list is adjusted to zero elements, thus discarding all returned values. If an expression is used as the last (or the only) element of a list of expressions, then no adjustment is made (unless the expression is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, either discarding all values except the first one or adding a single nil if there are no values.

Here are some examples:

     f()                -- adjusted to 0 results
     g(f(), x)          -- f() is adjusted to 1 result
     g(x, f())          -- g gets x plus all results from f()
     a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
     a,b = ...          -- a gets the first vararg parameter, b gets
                        -- the second (both a and b can get nil if there
                        -- is no corresponding vararg parameter)
     
     a,b,c = x, f()     -- f() is adjusted to 2 results
     a,b,c = f()        -- f() is adjusted to 3 results
     return f()         -- returns all results from f()
     return ...         -- returns all received vararg parameters
     return x,y,f()     -- returns x, y, and all results from f()
     {f()}              -- creates a list with all results from f()
     {...}              -- creates a list with all vararg parameters
     {f(), nil}         -- f() is adjusted to 1 result

Any expression enclosed in parentheses always results in only one value. Thus, (f(x,y,z)) is always a single value, even if f returns several values. (The value of (f(x,y,z)) is the first value returned by f or nil if f does not return any values.)

3.4.1 – Arithmetic Operators

Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), / (division), % (modulo), and ^ (exponentiation); and unary - (mathematical negation). If the operands are numbers, or strings that can be converted to numbers (see §3.4.2), then all operations have the usual meaning. Exponentiation works for any exponent. For instance, x^(-0.5) computes the inverse of the square root of x. Modulo is defined as

     a % b == a - math.floor(a/b)*b

That is, it is the remainder of a division that rounds the quotient towards minus infinity.

3.4.2 – Coercion

Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the rules of the Lua lexer. (The string may have leading and trailing spaces and a sign.) Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, use the format function from the string library (see string.format).

3.4.3 – Relational Operators

The relational operators in Lua are

     ==    ~=    <     >     <=    >=

These operators always result in false or true.

Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Tables, userdata, and threads are compared by reference: two objects are considered equal only if they are the same object. Every time you create a new object (a table, userdata, or thread), this new object is different from any previously existing object. Closures with the same reference are always equal. Closures with any detectable difference (different behavior, different definition) are always different.

You can change the way that Lua compares tables and userdata by using the "eq" metamethod (see §2.4).

The conversion rules of §3.4.2 do not apply to equality comparisons. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table.

The operator ~= is exactly the negation of equality (==).

The order operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the "lt" or the "le" metamethod (see §2.4). A comparison a > b is translated to b < a and a >= b is translated to b <= a.

3.4.4 – Logical Operators

The logical operators in Lua are and, or, and not. Like the control structures (see §3.3.4), all logical operators consider both false and nil as false and anything else as true.

The negation operator not always returns false or true. The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument if this value is different from nil and false; otherwise, or returns its second argument. Both and and or use short-cut evaluation; that is, the second operand is evaluated only if necessary. Here are some examples:

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

(In this manual, --> indicates the result of the preceding expression.)

3.4.5 – Concatenation

The string concatenation operator in Lua is denoted by two dots ('..'). If both operands are strings or numbers, then they are converted to strings according to the rules mentioned in §3.4.2. Otherwise, the __concat metamethod is called (see §2.4).

3.4.6 – The Length Operator

The length operator is denoted by the unary prefix operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

A program can modify the behavior of the length operator for any value but strings through the __len metamethod (see §2.4).

Unless a __len metamethod is given, the length of a table t is only defined if the table is a sequence, that is, the set of its positive numeric keys is equal to {1..n} for some integer n. In that case, n is its length. Note that a table like

     {10, 20, nil, 40}

is not a sequence, because it has the key 4 but does not have the key 3. (So, there is no n such that the set {1..n} is equal to the set of positive numeric keys of that table.) Note, however, that non-numeric keys do not interfere with whether a table is a sequence.

3.4.7 – Precedence

Operator precedence in Lua follows the table below, from lower to higher priority:

     or
     and
     <     >     <=    >=    ~=    ==
     ..
     +     -
     *     /     %
     not   #     - (unary)
     ^

As usual, you can use parentheses to change the precedences of an expression. The concatenation ('..') and exponentiation ('^') operators are right associative. All other binary operators are left associative.

3.4.8 – Table Constructors

Table constructors are expressions that create tables. Every time a constructor is evaluated, a new table is created. A constructor can be used to create an empty table or to create a table and initialize some of its fields. The general syntax for constructors is

	tableconstructor ::= ‘{’ [fieldlist] ‘}’
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
	fieldsep ::= ‘,’ | ‘;

Each field of the form [exp1] = exp2 adds to the new table an entry with key exp1 and value exp2. A field of the form name = exp is equivalent to ["name"] = exp. Finally, fields of the form exp are equivalent to [i] = exp, where i are consecutive numerical integers, starting with 1. Fields in the other formats do not affect this counting. For example,

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

is equivalent to

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end

If the last field in the list has the form exp and the expression is a function call or a vararg expression, then all values returned by this expression enter the list consecutively (see §3.4.9).

The field list can have an optional trailing separator, as a convenience for machine-generated code.

3.4.9 – Function Calls

A function call in Lua has the following syntax:

	functioncall ::= prefixexp args

In a function call, first prefixexp and args are evaluated. If the value of prefixexp has type function, then this function is called with the given arguments. Otherwise, the prefixexp "call" metamethod is called, having as first parameter the value of prefixexp, followed by the original call arguments (see §2.4).

The form

	functioncall ::= prefixexp ‘:’ Name args

can be used to call "methods". A call v:name(args) is syntactic sugar for v.name(v,args), except that v is evaluated only once.

Arguments have the following syntax:

	args ::= ‘(’ [explist] ‘)’
	args ::= tableconstructor
	args ::= String

All argument expressions are evaluated before the call. A call of the form f{fields} is syntactic sugar for f({fields}); that is, the argument list is a single new table. A call of the form f'string' (or f"string" or f[[string]]) is syntactic sugar for f('string'); that is, the argument list is a single literal string.

A call of the form return functioncall is called a tail call. Lua implements proper tail calls (or proper tail recursion): in a tail call, the called function reuses the stack entry of the calling function. Therefore, there is no limit on the number of nested tail calls that a program can execute. However, a tail call erases any debug information about the calling function. Note that a tail call only happens with a particular syntax, where the return has one single function call as argument; this syntax makes the calling function return exactly the returns of the called function. So, none of the following examples are tail calls:

     return (f(x))        -- results adjusted to 1
     return 2 * f(x)
     return x, f(x)       -- additional results
     f(x); return         -- results discarded
     return x or f(x)     -- results adjusted to 1

3.4.10 – Function Definitions

The syntax for function definition is

	functiondef ::= function funcbody
	funcbody ::= ‘(’ [parlist] ‘)’ block end

The following syntactic sugar simplifies function definitions:

	stat ::= function funcname funcbody
	stat ::= local function Name funcbody
	funcname ::= Name {‘.’ Name} [‘:’ Name]

The statement

     function f () body end

translates to

     f = function () body end

The statement

     function t.a.b.c.f () body end

translates to

     t.a.b.c.f = function () body end

The statement

     local function f () body end

translates to

     local f; f = function () body end

not to

     local f = function () body end

(This only makes a difference when the body of the function contains references to f.)

A function definition is an executable expression, whose value has type function. When Lua precompiles a chunk, all its function bodies are precompiled too. Then, whenever Lua executes the function definition, the function is instantiated (or closed). This function instance (or closure) is the final value of the expression.

Parameters act as local variables that are initialized with the argument values:

	parlist ::= namelist [‘,’ ‘...’] | ‘...

When a function is called, the list of arguments is adjusted to the length of the list of parameters, unless the function is a vararg function, which is indicated by three dots ('...') at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, which is also written as three dots. The value of this expression is a list of all actual extra arguments, similar to a function with multiple results. If a vararg expression is used inside another expression or in the middle of a list of expressions, then its return list is adjusted to one element. If the expression is used as the last element of a list of expressions, then no adjustment is made (unless that last expression is enclosed in parentheses).

As an example, consider the following definitions:

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end

Then, we have the following mapping from arguments to parameters and to the vararg expression:

     CALL            PARAMETERS
     
     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2
     
     g(3)             a=3, b=nil, ... -->  (nothing)
     g(3, 4)          a=3, b=4,   ... -->  (nothing)
     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
     g(5, r())        a=5, b=1,   ... -->  2  3

Results are returned using the return statement (see §3.3.4). If control reaches the end of a function without encountering a return statement, then the function returns with no results.

There is a system-dependent limit on the number of values that a function may return. This limit is guaranteed to be larger than 1000.

The colon syntax is used for defining methods, that is, functions that have an implicit extra parameter self. Thus, the statement

     function t.a.b.c:f (params) body end

is syntactic sugar for

     t.a.b.c.f = function (self, params) body end

3.5 – Visibility Rules

Lua is a lexically scoped language. The scope of a local variable begins at the first statement after its declaration and lasts until the last non-void statement of the innermost block that includes the declaration. Consider the following example:

     x = 10                -- global variable
     do                    -- new block
       local x = x         -- new 'x', with value 10
       print(x)            --> 10
       x = x+1
       do                  -- another block
         local x = x+1     -- another 'x'
         print(x)          --> 12
       end
       print(x)            --> 11
     end
     print(x)              --> 10  (the global one)

Notice that, in a declaration like local x = x, the new x being declared is not in scope yet, and so the second x refers to the outside variable.

Because of the lexical scoping rules, local variables can be freely accessed by functions defined inside their scope. A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function.

Notice that each execution of a local statement defines new local variables. Consider the following example:

     a = {}
     local x = 20
     for i=1,10 do
       local y = 0
       a[i] = function () y=y+1; return x+y end
     end

The loop creates ten closures (that is, ten instances of the anonymous function). Each of these closures uses a different y variable, while all of them share the same x.

4 – The Application Program Interface

This section describes the C API for Lua, that is, the set of C functions available to the host program to communicate with Lua. All API functions and related types and constants are declared in the header file lua.h.

Even when we use the term "function", any facility in the API may be provided as a macro instead. Except where stated otherwise, all such macros use each of their arguments exactly once (except for the first argument, which is always a Lua state), and so do not generate any hidden side-effects.

As in most C libraries, the Lua API functions do not check their arguments for validity or consistency. However, you can change this behavior by compiling Lua with the macro LUA_USE_APICHECK defined.

4.1 – The Stack

Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value (nil, number, string, etc.).

Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active. This stack initially contains any arguments to the C function and it is where the C function pushes its results to be returned to the caller (see lua_CFunction).

For convenience, most query operations in the API do not follow a strict stack discipline. Instead, they can refer to any element in the stack by using an index: A positive index represents an absolute stack position (starting at 1); a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, then index 1 represents the first element (that is, the element that was pushed onto the stack first) and index n represents the last element; index -1 also represents the last element (that is, the element at the top) and index -n represents the first element.

4.2 – Stack Size

When you interact with the Lua API, you are responsible for ensuring consistency. In particular, you are responsible for controlling stack overflow. You can use the function lua_checkstack to ensure that the stack has extra slots when pushing new elements.

Whenever Lua calls C, it ensures that the stack has at least LUA_MINSTACK extra slots. LUA_MINSTACK is defined as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack.

When you call a Lua function without a fixed number of results (see lua_call), Lua ensures that the stack has enough size for all results, but it does not ensure any extra space. So, before pushing anything in the stack after such a call you should use lua_checkstack.

4.3 – Valid and Acceptable Indices

Any function in the API that receives stack indices works only with valid indices or acceptable indices.

A valid index is an index that refers to a real position within the stack, that is, its position lies between 1 and the stack top (1 ≤ abs(index) ≤ top). Usually, functions that can modify the value at an index require valid indices.

Unless otherwise noted, any function that accepts valid indices also accepts pseudo-indices, which represent some Lua values that are accessible to C code but which are not in the stack. Pseudo-indices are used to access the registry and the upvalues of a C function (see §4.4).

Functions that do not need a specific stack position, but only a value in the stack (e.g., query functions), can be called with acceptable indices. An acceptable index can be any valid index, including the pseudo-indices, but it also can be any positive index after the stack top within the space allocated for the stack, that is, indices up to the stack size. (Note that 0 is never an acceptable index.) Except when noted otherwise, functions in the API work with acceptable indices.

Acceptable indices serve to avoid extra tests against the stack top when querying the stack. For instance, a C function can query its third argument without the need to first check whether there is a third argument, that is, without the need to check whether 3 is a valid index.

For functions that can be called with acceptable indices, any non-valid index is treated as if it contains a value of a virtual type LUA_TNONE, which behaves like a nil value.

4.4 – C Closures

When a C function is created, it is possible to associate some values with it, thus creating a C closure (see lua_pushcclosure); these values are called upvalues and are accessible to the function whenever it is called.

Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the current function (but not greater than 256), produces an acceptable but invalid index.

4.5 – Registry

Lua provides a registry, a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index LUA_REGISTRYINDEX, which is a valid index. Any C library can store data into this table, but it should take care to choose keys that are different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code, or any Lua object created by your code. As with global names, string keys starting with an underscore followed by uppercase letters are reserved for Lua.

The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, and by some predefined values. Therefore, integer keys should not be used for other purposes.

When you create a new Lua state, its registry comes with some predefined values. These predefined values are indexed with integer keys defined as constants in lua.h. The following constants are defined:

  • LUA_RIDX_MAINTHREAD: At this index the registry has the main thread of the state. (The main thread is the one created together with the state.)
  • LUA_RIDX_GLOBALS: At this index the registry has the global environment.

4.6 – Error Handling in C

Internally, Lua uses the C longjmp facility to handle errors. (You can also choose to use exceptions if you compile Lua as C++; search for LUAI_THROW in the source code.) When Lua faces any error (such as a memory allocation error, type errors, syntax errors, and runtime errors) it raises an error; that is, it does a long jump. A protected environment uses setjmp to set a recovery point; any error jumps to the most recent active recovery point.

If an error happens outside any protected environment, Lua calls a panic function (see lua_atpanic) and then calls abort, thus exiting the host application. Your panic function can avoid this exit by never returning (e.g., doing a long jump to your own recovery point outside Lua).

The panic function runs as if it were a message handler (see §2.3); in particular, the error message is at the top of the stack. However, there is no guarantees about stack space. To push anything on the stack, the panic function should first check the available space (see §4.2).

Most functions in the API can throw an error, for instance due to a memory allocation error. The documentation for each function indicates whether it can throw errors.

Inside a C function you can throw an error by calling lua_error.

4.7 – Handling Yields in C

Internally, Lua uses the C longjmp facility to yield a coroutine. Therefore, if a function foo calls an API function and this API function yields (directly or indirectly by calling another function that yields), Lua cannot return to foo any more, because the longjmp removes its frame from the C stack.

To avoid this kind of problem, Lua raises an error whenever it tries to yield across an API call, except for three functions: lua_yieldk, lua_callk, and lua_pcallk. All those functions receive a continuation function (as a parameter called k) to continue execution after a yield.

We need to set some terminology to explain continuations. We have a C function called from Lua which we will call the original function. This original function then calls one of those three functions in the C API, which we will call the callee function, that then yields the current thread. (This can happen when the callee function is lua_yieldk, or when the callee function is either lua_callk or lua_pcallk and the function called by them yields.)

Suppose the running thread yields while executing the callee function. After the thread resumes, it eventually will finish running the callee function. However, the callee function cannot return to the original function, because its frame in the C stack was destroyed by the yield. Instead, Lua calls a continuation function, which was given as an argument to the callee function. As the name implies, the continuation function should continue the task of the original function.

Lua treats the continuation function as if it were the original function. The continuation function receives the same Lua stack from the original function, in the same state it would be if the callee function had returned. (For instance, after a lua_callk the function and its arguments are removed from the stack and replaced by the results from the call.) It also has the same upvalues. Whatever it returns is handled by Lua as if it were the return of the original function.

The only difference in the Lua state between the original function and its continuation is the result of a call to lua_getctx.

4.8 – Functions and Types

Here we list all functions and types from the C API in alphabetical order. Each function has an indicator like this: [-o, +p, x]

The first field, o, is how many elements the function pops from the stack. The second field, p, is how many elements the function pushes onto the stack. (Any function always pushes its results after popping its arguments.) A field in the form x|y means the function can push (or pop) x or y elements, depending on the situation; an interrogation mark '?' means that we cannot know how many elements the function pops/pushes by looking only at its arguments (e.g., they may depend on what is on the stack). The third field, x, tells whether the function may throw errors: '-' means the function never throws any error; 'e' means the function may throw errors; 'v' means the function may throw an error on purpose.


lua_absindex

[-0, +0, –]

int lua_absindex (lua_State *L, int idx);

Converts the acceptable index idx into an absolute index (that is, one that does not depend on the stack top).


lua_Alloc

typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);

The type of the memory-allocation function used by Lua states. The allocator function must provide a functionality similar to realloc, but not exactly the same. Its arguments are ud, an opaque pointer passed to lua_newstate; ptr, a pointer to the block being allocated/reallocated/freed; osize, the original size of the block or some code about what is being allocated; nsize, the new size of the block.

When ptr is not NULL, osize is the size of the block pointed by ptr, that is, the size given when it was allocated or reallocated.

When ptr is NULL, osize encodes the kind of object that Lua is allocating. osize is any of LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, or LUA_TTHREAD when (and only when) Lua is creating a new object of that type. When osize is some other value, Lua is allocating memory for something else.

Lua assumes the following behavior from the allocator function:

When nsize is zero, the allocator should behave like free and return NULL.

When nsize is not zero, the allocator should behave like realloc. The allocator returns NULL if and only if it cannot fulfill the request. Lua assumes that the allocator never fails when osize >= nsize.

Here is a simple implementation for the allocator function. It is used in the auxiliary library by luaL_newstate.

     static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                size_t nsize) {
       (void)ud;  (void)osize;  /* not used */
       if (nsize == 0) {
         free(ptr);
         return NULL;
       }
       else
         return realloc(ptr, nsize);
     }

Note that Standard C ensures that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). This code assumes that realloc does not fail when shrinking a block. (Although Standard C does not ensure this behavior, it seems to be a safe assumption.)


lua_arith

[-(2|1), +1, e]

void lua_arith (lua_State *L, int op);

Performs an arithmetic operation over the two values (or one, in the case of negation) at the top of the stack, with the value at the top being the second operand, pops these values, and pushes the result of the operation. The function follows the semantics of the corresponding Lua operator (that is, it may call metamethods).

The value of op must be one of the following constants:


lua_atpanic

[-0, +0, –]

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

Sets a new panic function and returns the old one (see §4.6).


lua_call

[-(nargs+1), +nresults, e]

void lua_call (lua_State *L, int nargs, int nresults);

Calls a function.

To call a function you must use the following protocol: first, the function to be called is pushed onto the stack; then, the arguments to the function are pushed in direct order; that is, the first argument is pushed first. Finally you call lua_call; nargs is the number of arguments that you pushed onto the stack. All arguments and the function value are popped from the stack when the function is called. The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top of the stack.

Any error inside the called function is propagated upwards (with a longjmp).

The following example shows how the host program can do the equivalent to this Lua code:

     a = f("how", t.x, 14)

Here it is in C:

     lua_getglobal(L, "f");                  /* function to be called */
     lua_pushstring(L, "how");                        /* 1st argument */
     lua_getglobal(L, "t");                    /* table to be indexed */
     lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
     lua_remove(L, -2);                  /* remove 't' from the stack */
     lua_pushinteger(L, 14);                          /* 3rd argument */
     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
     lua_setglobal(L, "a");                         /* set global 'a' */

Note that the code above is "balanced": at its end, the stack is back to its original configuration. This is considered good programming practice.


lua_callk

[-(nargs + 1), +nresults, e]

void lua_callk (lua_State *L, int nargs, int nresults, int ctx,
                lua_CFunction k);

This function behaves exactly like lua_call, but allows the called function to yield (see §4.7).


lua_CFunction

typedef int (*lua_CFunction) (lua_State *L);

Type for C functions.

In order to communicate properly with Lua, a C function must use the following protocol, which defines the way parameters and results are passed: a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). So, when the function starts, lua_gettop(L) returns the number of arguments received by the function. The first argument (if any) is at index 1 and its last argument is at index lua_gettop(L). To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results. Any other value in the stack below the results will be properly discarded by Lua. Like a Lua function, a C function called by Lua can also return many results.

As an example, the following function receives a variable number of numerical arguments and returns their average and sum:

     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* number of arguments */
       lua_Number sum = 0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushstring(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);        /* first result */
       lua_pushnumber(L, sum);         /* second result */
       return 2;                   /* number of results */
     }

lua_checkstack

[-0, +0, –]

int lua_checkstack (lua_State *L, int extra);

Ensures that there are at least extra free stack slots in the stack. It returns false if it cannot fulfill the request, because it would cause the stack to be larger than a fixed maximum size (typically at least a few thousand elements) or because it cannot allocate memory for the new stack size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged.


lua_close

[-0, +0, –]

void lua_close (lua_State *L);

Destroys all objects in the given Lua state (calling the corresponding garbage-collection metamethods, if any) and frees all dynamic memory used by this state. On several platforms, you may not need to call this function, because all resources are naturally released when the host program ends. On the other hand, long-running programs that create multiple states, such as daemons or web servers, might need to close states as soon as they are not needed.


lua_compare

[-0, +0, e]

int lua_compare (lua_State *L, int index1, int index2, int op);

Compares two Lua values. Returns 1 if the value at index index1 satisfies op when compared with the value at index index2, following the semantics of the corresponding Lua operator (that is, it may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non valid.

The value of op must be one of the following constants:


lua_concat

[-n, +1, e]

void lua_concat (lua_State *L, int n);

Concatenates the n values at the top of the stack, pops them, and leaves the result at the top. If n is 1, the result is the single value on the stack (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is performed following the usual semantics of Lua (see §3.4.5).


lua_copy

[-0, +0, –]

void lua_copy (lua_State *L, int fromidx, int toidx);

Moves the element at index fromidx into the valid index toidx without shifting any element (therefore replacing the value at that position).


lua_createtable

[-0, +1, e]

void lua_createtable (lua_State *L, int narr, int nrec);

Creates a new empty table and pushes it onto the stack. Parameter narr is a hint for how many elements the table will have as a sequence; parameter nrec is a hint for how many other elements the table will have. Lua may use these hints to preallocate memory for the new table. This pre-allocation is useful for performance when you know in advance how many elements the table will have. Otherwise you can use the function lua_newtable.


lua_dump

[-0, +0, e]

int lua_dump (lua_State *L, lua_Writer writer, void *data);

Dumps a function as a binary chunk. Receives a Lua function on the top of the stack and produces a binary chunk that, if loaded again, results in a function equivalent to the one dumped. As it produces parts of the chunk, lua_dump calls function writer (see lua_Writer) with the given data to write them.

The value returned is the error code returned by the last call to the writer; 0 means no errors.

This function does not pop the Lua function from the stack.


lua_error

[-1, +0, v]

int lua_error (lua_State *L);

Generates a Lua error. The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, and therefore never returns (see luaL_error).


lua_gc

[-0, +0, e]

int lua_gc (lua_State *L, int what, int data);

Controls the garbage collector.

This function performs several tasks, according to the value of the parameter what:

  • LUA_GCSTOP: stops the garbage collector.
  • LUA_GCRESTART: restarts the garbage collector.
  • LUA_GCCOLLECT: performs a full garbage-collection cycle.
  • LUA_GCCOUNT: returns the current amount of memory (in Kbytes) in use by Lua.
  • LUA_GCCOUNTB: returns the remainder of dividing the current amount of bytes of memory in use by Lua by 1024.
  • LUA_GCSTEP: performs an incremental step of garbage collection. The step "size" is controlled by data (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of data. The function returns 1 if the step finished a garbage-collection cycle.
  • LUA_GCSETPAUSE: sets data as the new value for the pause of the collector (see §2.5). The function returns the previous value of the pause.
  • LUA_GCSETSTEPMUL: sets data as the new value for the step multiplier of the collector (see §2.5). The function returns the previous value of the step multiplier.
  • LUA_GCISRUNNING: returns a boolean that tells whether the collector is running (i.e., not stopped).
  • LUA_GCGEN: changes the collector to generational mode (see §2.5).
  • LUA_GCINC: changes the collector to incremental mode. This is the default mode.

For more details about these options, see collectgarbage.


lua_getallocf

[-0, +0, –]

lua_Alloc lua_getallocf (lua_State *L, void **ud);

Returns the memory-allocation function of a given state. If ud is not NULL, Lua stores in *ud the opaque pointer passed to lua_newstate.


lua_getctx

[-0, +0, –]

int lua_getctx (lua_State *L, int *ctx);

This function is called by a continuation function (see §4.7) to retrieve the status of the thread and a context information.

When called in the original function, lua_getctx always returns LUA_OK and does not change the value of its argument ctx. When called inside a continuation function, lua_getctx returns LUA_YIELD and sets the value of ctx to be the context information (the value passed as the ctx argument to the callee together with the continuation function).

When the callee is lua_pcallk, Lua may also call its continuation function to handle errors during the call. That is, upon an error in the function called by lua_pcallk, Lua may not return to the original function but instead may call the continuation function. In that case, a call to lua_getctx will return the error code (the value that would be returned by lua_pcallk); the value of ctx will be set to the context information, as in the case of a yield.


lua_getfield

[-0, +1, e]

void lua_getfield (lua_State *L, int index, const char *k);

Pushes onto the stack the value t[k], where t is the value at the given index. As in Lua, this function may trigger a metamethod for the "index" event (see §2.4).


lua_getglobal

[-0, +1, e]

void lua_getglobal (lua_State *L, const char *name);

Pushes onto the stack the value of the global name.


lua_getmetatable

[-0, +(0|1), –]

int lua_getmetatable (lua_State *L, int index);

Pushes onto the stack the metatable of the value at the given index. If the value does not have a metatable, the function returns 0 and pushes nothing on the stack.


lua_gettable

[-1, +1, e]

void lua_gettable (lua_State *L, int index);

Pushes onto the stack the value t[k], where t is the value at the given index and k is the value at the top of the stack.

This function pops the key from the stack (putting the resulting value in its place). As in Lua, this function may trigger a metamethod for the "index" event (see §2.4).


lua_gettop

[-0, +0, –]

int lua_gettop (lua_State *L);

Returns the index of the top element in the stack. Because indices start at 1, this result is equal to the number of elements in the stack (and so 0 means an empty stack).


lua_getuservalue

[-0, +1, –]

void lua_getuservalue (lua_State *L, int index);

Pushes onto the stack the Lua value associated with the userdata at the given index. This Lua value must be a table or nil.


lua_insert

[-1, +1, –]

void lua_insert (lua_State *L, int index);

Moves the top element into the given valid index, shifting up the elements above this index to open space. This function cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.


lua_Integer

typedef ptrdiff_t lua_Integer;

The type used by the Lua API to represent signed integral values.

By default it is a ptrdiff_t, which is usually the largest signed integral type the machine handles "comfortably".


lua_isboolean

[-0, +0, –]

int lua_isboolean (lua_State *L, int index);

Returns 1 if the value at the given index is a boolean, and 0 otherwise.


lua_iscfunction

[-0, +0, –]

int lua_iscfunction (lua_State *L, int index);

Returns 1 if the value at the given index is a C function, and 0 otherwise.


lua_isfunction

[-0, +0, –]

int lua_isfunction (lua_State *L, int index);

Returns 1 if the value at the given index is a function (either C or Lua), and 0 otherwise.


lua_islightuserdata

[-0, +0, –]

int lua_islightuserdata (lua_State *L, int index);

Returns 1 if the value at the given index is a light userdata, and 0 otherwise.


lua_isnil

[-0, +0, –]

int lua_isnil (lua_State *L, int index);

Returns 1 if the value at the given index is nil, and 0 otherwise.


lua_isnone

[-0, +0, –]

int lua_isnone (lua_State *L, int index);

Returns 1 if the given index is not valid, and 0 otherwise.


lua_isnoneornil

[-0, +0, –]

int lua_isnoneornil (lua_State *L, int index);

Returns 1 if the given index is not valid or if the value at this index is nil, and 0 otherwise.


lua_isnumber

[-0, +0, –]

int lua_isnumber (lua_State *L, int index);

Returns 1 if the value at the given index is a number or a string convertible to a number, and 0 otherwise.


lua_isstring

[-0, +0, –]

int lua_isstring (lua_State *L, int index);

Returns 1 if the value at the given index is a string or a number (which is always convertible to a string), and 0 otherwise.


lua_istable

[-0, +0, –]

int lua_istable (lua_State *L, int index);

Returns 1 if the value at the given index is a table, and 0 otherwise.


lua_isthread

[-0, +0, –]

int lua_isthread (lua_State *L, int index);

Returns 1 if the value at the given index is a thread, and 0 otherwise.


lua_isuserdata

[-0, +0, –]

int lua_isuserdata (lua_State *L, int index);

Returns 1 if the value at the given index is a userdata (either full or light), and 0 otherwise.


lua_len

[-0, +1, e]

void lua_len (lua_State *L, int index);

Returns the "length" of the value at the given index; it is equivalent to the '#' operator in Lua (see §3.4.6). The result is pushed on the stack.


lua_load

[-0, +1, –]

int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *source,
              const char *mode);

Loads a Lua chunk (without running it). If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it pushes an error message.

The return values of lua_load are:

  • LUA_OK: no errors;
  • LUA_ERRSYNTAX: syntax error during precompilation;
  • LUA_ERRMEM: memory allocation error;
  • LUA_ERRGCMM: error while running a __gc metamethod. (This error has no relation with the chunk being loaded. It is generated by the garbage collector.)

The lua_load function uses a user-supplied reader function to read the chunk (see lua_Reader). The data argument is an opaque value passed to the reader function.

The source argument gives a name to the chunk, which is used for error messages and in debug information (see §4.9).

lua_load automatically detects whether the chunk is text or binary and loads it accordingly (see program luac). The string mode works as in function load, with the addition that a NULL value is equivalent to the string "bt".

lua_load uses the stack internally, so the reader function should always leave the stack unmodified when returning.

If the resulting function has one upvalue, this upvalue is set to the value of the global environment stored at index LUA_RIDX_GLOBALS in the registry (see §4.5). When loading main chunks, this upvalue will be the _ENV variable (see §2.2).


lua_newstate

[-0, +0, –]

lua_State *lua_newstate (lua_Alloc f, void *ud);

Creates a new thread running in a new, independent state. Returns NULL if cannot create the thread or the state (due to lack of memory). The argument f is the allocator function; Lua does all memory allocation for this state through this function. The second argument, ud, is an opaque pointer that Lua passes to the allocator in every call.


lua_newtable

[-0, +1, e]

void lua_newtable (lua_State *L);

Creates a new empty table and pushes it onto the stack. It is equivalent to lua_createtable(L, 0, 0).


lua_newthread

[-0, +1, e]

lua_State *lua_newthread (lua_State *L);

Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. The new thread returned by this function shares with the original thread its global environment, but has an independent execution stack.

There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object.


lua_newuserdata

[-0, +1, e]

void *lua_newuserdata (lua_State *L, size_t size);

This function allocates a new block of memory with the given size, pushes onto the stack a new full userdata with the block address, and returns this address. The host program can freely use this memory.


lua_next

[-1, +(2|0), e]

int lua_next (lua_State *L, int index);

Pops a key from the stack, and pushes a key–value pair from the table at the given index (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns 0 (and pushes nothing).

A typical traversal looks like this:

     /* table is in the stack at index 't' */
     lua_pushnil(L);  /* first key */
     while (lua_next(L, t) != 0) {
       /* uses 'key' (at index -2) and 'value' (at index -1) */
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* removes 'value'; keeps 'key' for next iteration */
       lua_pop(L, 1);
     }

While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. Recall that lua_tolstring may change the value at the given index; this confuses the next call to lua_next.

See function next for the caveats of modifying the table during its traversal.


lua_Number

typedef double lua_Number;

The type of numbers in Lua. By default, it is double, but that can be changed in luaconf.h. Through this configuration file you can change Lua to operate with another type for numbers (e.g., float or long).


lua_pcall

[-(nargs + 1), +(nresults|1), –]

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

Calls a function in protected mode.

Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, pushes a single value on the stack (the error message), and returns an error code. Like lua_call, lua_pcall always removes the function and its arguments from the stack.

If msgh is 0, then the error message returned on the stack is exactly the original error message. Otherwise, msgh is the stack index of a message handler. (In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall.

Typically, the message handler is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.

The lua_pcall function returns one of the following codes (defined in lua.h):

  • LUA_OK (0): success.
  • LUA_ERRRUN: a runtime error.
  • LUA_ERRMEM: memory allocation error. For such errors, Lua does not call the message handler.
  • LUA_ERRERR: error while running the message handler.
  • LUA_ERRGCMM: error while running a __gc metamethod. (This error typically has no relation with the function being called. It is generated by the garbage collector.)

lua_pcallk

[-(nargs + 1), +(nresults|1), –]

int lua_pcallk (lua_State *L,
                int nargs,
                int nresults,
                int errfunc,
                int ctx,
                lua_CFunction k);

This function behaves exactly like lua_pcall, but allows the called function to yield (see §4.7).


lua_pop

[-n, +0, –]

void lua_pop (lua_State *L, int n);

Pops n elements from the stack.


lua_pushboolean

[-0, +1, –]

void lua_pushboolean (lua_State *L, int b);

Pushes a boolean value with value b onto the stack.


lua_pushcclosure

[-n, +1, e]

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

Pushes a new C closure onto the stack.

When a C function is created, it is possible to associate some values with it, thus creating a C closure (see §4.4); these values are then accessible to the function whenever it is called. To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then lua_pushcclosure is called to create and push the C function onto the stack, with the argument n telling how many values should be associated with the function. lua_pushcclosure also pops these values from the stack.

The maximum value for n is 255.

When n is zero, this function creates a light C function, which is just a pointer to the C function. In that case, it never throws a memory error.


lua_pushcfunction

[-0, +1, –]

void lua_pushcfunction (lua_State *L, lua_CFunction f);

Pushes a C function onto the stack. This function receives a pointer to a C function and pushes onto the stack a Lua value of type function that, when called, invokes the corresponding C function.

Any function to be registered in Lua must follow the correct protocol to receive its parameters and return its results (see lua_CFunction).

lua_pushcfunction is defined as a macro:

     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)

Note that f is used twice.


lua_pushfstring

[-0, +1, e]

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

Pushes onto the stack a formatted string and returns a pointer to this string. It is similar to the ANSI C function sprintf, but has some important differences:

  • You do not have to allocate space for the result: the result is a Lua string and Lua takes care of memory allocation (and deallocation, through garbage collection).
  • The conversion specifiers are quite restricted. There are no flags, widths, or precisions. The conversion specifiers can only be '%%' (inserts a '%' in the string), '%s' (inserts a zero-terminated string, with no size restrictions), '%f' (inserts a lua_Number), '%p' (inserts a pointer as a hexadecimal numeral), '%d' (inserts an int), and '%c' (inserts an int as a byte).

lua_pushglobaltable

[-0, +1, –]

void lua_pushglobaltable (lua_State *L);

Pushes the global environment onto the stack.


lua_pushinteger

[-0, +1, –]

void lua_pushinteger (lua_State *L, lua_Integer n);

Pushes a number with value n onto the stack.


lua_pushlightuserdata

[-0, +1, –]

void lua_pushlightuserdata (lua_State *L, void *p);

Pushes a light userdata onto the stack.

Userdata represent C values in Lua. A light userdata represents a pointer, a void*. It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). A light userdata is equal to "any" light userdata with the same C address.


lua_pushliteral

[-0, +1, e]

const char *lua_pushliteral (lua_State *L, const char *s);

This macro is equivalent to lua_pushlstring, but can be used only when s is a literal string. It automatically provides the string length.


lua_pushlstring

[-0, +1, e]

const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

Pushes the string pointed to by s with size len onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string can contain any binary data, including embedded zeros.

Returns a pointer to the internal copy of the string.


lua_pushnil

[-0, +1, –]

void lua_pushnil (lua_State *L);

Pushes a nil value onto the stack.


lua_pushnumber

[-0, +1, –]

void lua_pushnumber (lua_State *L, lua_Number n);

Pushes a number with value n onto the stack.


lua_pushstring

[-0, +1, e]

const char *lua_pushstring (lua_State *L, const char *s);

Pushes the zero-terminated string pointed to by s onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns.

Returns a pointer to the internal copy of the string.

If s is NULL, pushes nil and returns NULL.


lua_pushthread

[-0, +1, –]

int lua_pushthread (lua_State *L);

Pushes the thread represented by L onto the stack. Returns 1 if this thread is the main thread of its state.


lua_pushunsigned

[-0, +1, –]

void lua_pushunsigned (lua_State *L, lua_Unsigned n);

Pushes a number with value n onto the stack.


lua_pushvalue

[-0, +1, –]

void lua_pushvalue (lua_State *L, int index);

Pushes a copy of the element at the given index onto the stack.


lua_pushvfstring

[-0, +1, e]

const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);

Equivalent to lua_pushfstring, except that it receives a va_list instead of a variable number of arguments.


lua_rawequal

[-0, +0, –]

int lua_rawequal (lua_State *L, int index1, int index2);

Returns 1 if the two values in indices index1 and index2 are primitively equal (that is, without calling metamethods). Otherwise returns 0. Also returns 0 if any of the indices are non valid.


lua_rawget

[-1, +1, –]

void lua_rawget (lua_State *L, int index);

Similar to lua_gettable, but does a raw access (i.e., without metamethods).


lua_rawgeti

[-0, +1, –]

void lua_rawgeti (lua_State *L, int index, int n);

Pushes onto the stack the value t[n], where t is the table at the given index. The access is raw; that is, it does not invoke metamethods.


lua_rawgetp

[-0, +1, –]

void lua_rawgetp (lua_State *L, int index, const void *p);

Pushes onto the stack the value t[k], where t is the table at the given index and k is the pointer p represented as a light userdata. The access is raw; that is, it does not invoke metamethods.


lua_rawlen

[-0, +0, –]

size_t lua_rawlen (lua_State *L, int index);

Returns the raw "length" of the value at the given index: for strings, this is the string length; for tables, this is the result of the length operator ('#') with no metamethods; for userdata, this is the size of the block of memory allocated for the userdata; for other values, it is 0.


lua_rawset

[-2, +0, e]

void lua_rawset (lua_State *L, int index);

Similar to lua_settable, but does a raw assignment (i.e., without metamethods).


lua_rawseti

[-1, +0, e]

void lua_rawseti (lua_State *L, int index, int n);

Does the equivalent of t[n] = v, where t is the table at the given index and v is the value at the top of the stack.

This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods.


lua_rawsetp

[-1, +0, e]

void lua_rawsetp (lua_State *L, int index, const void *p);

Does the equivalent of t[k] = v, where t is the table at the given index, k is the pointer p represented as a light userdata, and v is the value at the top of the stack.

This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods.


lua_Reader

typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);

The reader function used by lua_load. Every time it needs another piece of the chunk, lua_load calls the reader, passing along its data parameter. The reader must return a pointer to a block of memory with a new piece of the chunk and set size to the block size. The block must exist until the reader function is called again. To signal the end of the chunk, the reader must return NULL or set size to zero. The reader function may return pieces of any size greater than zero.


lua_register

[-0, +0, e]

void lua_register (lua_State *L, const char *name, lua_CFunction f);

Sets the C function f as the new value of global name. It is defined as a macro:

     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))

lua_remove

[-1, +0, –]

void lua_remove (lua_State *L, int index);

Removes the element at the given valid index, shifting down the elements above this index to fill the gap. This function cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.


lua_replace

[-1, +0, –]

void lua_replace (lua_State *L, int index);

Moves the top element into the given valid index without shifting any element (therefore replacing the value at the given index), and then pops the top element.


lua_resume

[-?, +?, –]

int lua_resume (lua_State *L, lua_State *from, int nargs);

Starts and resumes a coroutine in a given thread.

To start a coroutine, you push onto the thread stack the main function plus any arguments; then you call lua_resume, with nargs being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. lua_resume returns LUA_YIELD if the coroutine yields, LUA_OK if the coroutine finishes its execution without errors, or an error code in case of errors (see lua_pcall).

In case of errors, the stack is not unwound, so you can use the debug API over it. The error message is on the top of the stack.

To resume a coroutine, you remove any results from the last lua_yield, put on its stack only the values to be passed as results from yield, and then call lua_resume.

The parameter from represents the coroutine that is resuming L. If there is no such coroutine, this parameter can be NULL.


lua_setallocf

[-0, +0, –]

void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

Changes the allocator function of a given state to f with user data ud.


lua_setfield

[-1, +0, e]

void lua_setfield (lua_State *L, int index, const char *k);

Does the equivalent to t[k] = v, where t is the value at the given index and v is the value at the top of the stack.

This function pops the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event (see §2.4).


lua_setglobal

[-1, +0, e]

void lua_setglobal (lua_State *L, const char *name);

Pops a value from the stack and sets it as the new value of global name.


lua_setmetatable

[-1, +0, –]

void lua_setmetatable (lua_State *L, int index);

Pops a table from the stack and sets it as the new metatable for the value at the given index.


lua_settable

[-2, +0, e]

void lua_settable (lua_State *L, int index);

Does the equivalent to t[k] = v, where t is the value at the given index, v is the value at the top of the stack, and k is the value just below the top.

This function pops both the key and the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event (see §2.4).


lua_settop

[-?, +?, –]

void lua_settop (lua_State *L, int index);

Accepts any index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. If index is 0, then all stack elements are removed.


lua_setuservalue

[-1, +0, –]

void lua_setuservalue (lua_State *L, int index);

Pops a table or nil from the stack and sets it as the new value associated to the userdata at the given index.


lua_State

typedef struct lua_State lua_State;

An opaque structure that points to a thread and indirectly (through the thread) to the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. All information about a state is accessible through this structure.

A pointer to this structure must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch.


lua_status

[-0, +0, –]

int lua_status (lua_State *L);

Returns the status of the thread L.

The status can be 0 (LUA_OK) for a normal thread, an error code if the thread finished the execution of a lua_resume with an error, or LUA_YIELD if the thread is suspended.

You can only call functions in threads with status LUA_OK. You can resume threads with status LUA_OK (to start a new coroutine) or LUA_YIELD (to resume a coroutine).


lua_toboolean

[-0, +0, –]

int lua_toboolean (lua_State *L, int index);

Converts the Lua value at the given index to a C boolean value (0 or 1). Like all tests in Lua, lua_toboolean returns true for any Lua value different from false and nil; otherwise it returns false. (If you want to accept only actual boolean values, use lua_isboolean to test the value's type.)


lua_tocfunction

[-0, +0, –]

lua_CFunction lua_tocfunction (lua_State *L, int index);

Converts a value at the given index to a C function. That value must be a C function; otherwise, returns NULL.


lua_tointeger

[-0, +0, –]

lua_Integer lua_tointeger (lua_State *L, int index);

Equivalent to lua_tointegerx with isnum equal to NULL.


lua_tointegerx

[-0, +0, –]

lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

Converts the Lua value at the given index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §3.4.2); otherwise, lua_tointegerx returns 0.

If the number is not an integer, it is truncated in some non-specified way.

If isnum is not NULL, its referent is assigned a boolean value that indicates whether the operation succeeded.


lua_tolstring

[-0, +0, e]

const char *lua_tolstring (lua_State *L, int index, size_t *len);

Converts the Lua value at the given index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; otherwise, the function returns NULL. If the value is a number, then lua_tolstring also changes the actual value in the stack to a string. (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.)

lua_tolstring returns a fully aligned pointer to a string inside the Lua state. This string always has a zero ('\0') after its last character (as in C), but can contain other zeros in its body. Because Lua has garbage collection, there is no guarantee that the pointer returned by lua_tolstring will be valid after the corresponding value is removed from the stack.


lua_tonumber

[-0, +0, –]

lua_Number lua_tonumber (lua_State *L, int index);

Equivalent to lua_tonumberx with isnum equal to NULL.


lua_tonumberx

[-0, +0, –]

lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

Converts the Lua value at the given index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §3.4.2); otherwise, lua_tonumberx returns 0.

If isnum is not NULL, its referent is assigned a boolean value that indicates whether the operation succeeded.


lua_topointer

[-0, +0, –]

const void *lua_topointer (lua_State *L, int index);

Converts the value at the given index to a generic C pointer (void*). The value can be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. Different objects will give different pointers. There is no way to convert the pointer back to its original value.

Typically this function is used only for debug information.


lua_tostring

[-0, +0, e]

const char *lua_tostring (lua_State *L, int index);

Equivalent to lua_tolstring with len equal to NULL.


lua_tothread

[-0, +0, –]

lua_State *lua_tothread (lua_State *L, int index);

Converts the value at the given index to a Lua thread (represented as lua_State*). This value must be a thread; otherwise, the function returns NULL.


lua_tounsigned

[-0, +0, –]

lua_Unsigned lua_tounsigned (lua_State *L, int index);

Equivalent to lua_tounsignedx with isnum equal to NULL.


lua_tounsignedx

[-0, +0, –]

lua_Unsigned lua_tounsignedx (lua_State *L, int index, int *isnum);

Converts the Lua value at the given index to the unsigned integral type lua_Unsigned. The Lua value must be a number or a string convertible to a number (see §3.4.2); otherwise, lua_tounsignedx returns 0.

If the number is not an integer, it is truncated in some non-specified way. If the number is outside the range of representable values, it is normalized to the remainder of its division by one more than the maximum representable value.

If isnum is not NULL, its referent is assigned a boolean value that indicates whether the operation succeeded.


lua_touserdata

[-0, +0, –]

void *lua_touserdata (lua_State *L, int index);

If the value at the given index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. Otherwise, returns NULL.


lua_type

[-0, +0, –]

int lua_type (lua_State *L, int index);

Returns the type of the value in the given valid index, or LUA_TNONE for a non-valid (but acceptable) index. The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA.


lua_typename

[-0, +0, –]

const char *lua_typename (lua_State *L, int tp);

Returns the name of the type encoded by the value tp, which must be one the values returned by lua_type.


lua_Unsigned

typedef unsigned long lua_Unsigned;

The type used by the Lua API to represent unsigned integral values. It must have at least 32 bits.

By default it is an unsigned int or an unsigned long, whichever can hold 32-bit values.


lua_upvalueindex

[-0, +0, –]

int lua_upvalueindex (int i);

Returns the pseudo-index that represents the i-th upvalue of the running function (see §4.4).


lua_version

[-0, +0, v]

const lua_Number *lua_version (lua_State *L);

Returns the address of the version number stored in the Lua core. When called with a valid lua_State, returns the address of the version used to create that state. When called with NULL, returns the address of the version running the call.


lua_Writer

typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);

The type of the writer function used by lua_dump. Every time it produces another piece of chunk, lua_dump calls the writer, passing along the buffer to be written (p), its size (sz), and the data parameter supplied to lua_dump.

The writer returns an error code: 0 means no errors; any other value means an error and stops lua_dump from calling the writer again.


lua_xmove

[-?, +?, –]

void lua_xmove (lua_State *from, lua_State *to, int n);

Exchange values between different threads of the same state.

This function pops n values from the stack from, and pushes them onto the stack to.


lua_yield

[-?, +?, –]

int lua_yield (lua_State *L, int nresults);

This function is equivalent to lua_yieldk, but it has no continuation (see §4.7). Therefore, when the thread resumes, it returns to the function that called the function calling lua_yield.


lua_yieldk

[-?, +?, –]

int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k);

Yields a coroutine.

This function should only be called as the return expression of a C function, as follows:

     return lua_yieldk (L, n, i, k);

When a C function calls lua_yieldk in that way, the running coroutine suspends its execution, and the call to lua_resume that started this coroutine returns. The parameter nresults is the number of values from the stack that are passed as results to lua_resume.

When the coroutine is resumed again, Lua calls the given continuation function k to continue the execution of the C function that yielded (see §4.7). This continuation function receives the same stack from the previous function, with the results removed and replaced by the arguments passed to lua_resume. Moreover, the continuation function may access the value ctx by calling lua_getctx.

4.9 – The Debug Interface

Lua has no built-in debugging facilities. Instead, it offers a special interface by means of functions and hooks. This interface allows the construction of different kinds of debuggers, profilers, and other tools that need "inside information" from the interpreter.


lua_Debug

typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  int currentline;            /* (l) */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  unsigned char nups;         /* (u) number of upvalues */
  unsigned char nparams;      /* (u) number of parameters */
  char isvararg;              /* (u) */
  char istailcall;            /* (t) */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* private part */
  other fields
} lua_Debug;

A structure used to carry different pieces of information about a function or an activation record. lua_getstack fills only the private part of this structure, for later use. To fill the other fields of lua_Debug with useful information, call lua_getinfo.

The fields of lua_Debug have the following meaning:

  • source: the source of the chunk that created the function. If source starts with a '@', it means that the function was defined in a file where the file name follows the '@'. If source starts with a '=', the remainder of its contents describe the source in a user-dependent manner. Otherwise, the function was defined in a string where source is that string.
  • short_src: a "printable" version of source, to be used in error messages.
  • linedefined: the line number where the definition of the function starts.
  • lastlinedefined: the line number where the definition of the function ends.
  • what: the string "Lua" if the function is a Lua function, "C" if it is a C function, "main" if it is the main part of a chunk.
  • currentline: the current line where the given function is executing. When no line information is available, currentline is set to -1.
  • name: a reasonable name for the given function. Because functions in Lua are first-class values, they do not have a fixed name: some functions can be the value of multiple global variables, while others can be stored only in a table field. The lua_getinfo function checks how the function was called to find a suitable name. If it cannot find a name, then name is set to NULL.
  • namewhat: explains the name field. The value of namewhat can be "global", "local", "method", "field", "upvalue", or "" (the empty string), according to how the function was called. (Lua uses the empty string when no other option seems to apply.)
  • istailcall: true if this function invocation was called by a tail call. In this case, the caller of this level is not in the stack.
  • nups: the number of upvalues of the function.
  • nparams: the number of fixed parameters of the function (always 0 for C functions).
  • isvararg: true if the function is a vararg function (always true for C functions).

lua_gethook

[-0, +0, –]

lua_Hook lua_gethook (lua_State *L);

Returns the current hook function.


lua_gethookcount

[-0, +0, –]

int lua_gethookcount (lua_State *L);

Returns the current hook count.


lua_gethookmask

[-0, +0, –]

int lua_gethookmask (lua_State *L);

Returns the current hook mask.


lua_getinfo

[-(0|1), +(0|1|2), e]

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

Gets information about a specific function or function invocation.

To get information about a function invocation, the parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook).

To get information about a function you push it onto the stack and start the what string with the character '>'. (In that case, lua_getinfo pops the function from the top of the stack.) For instance, to know in which line a function f was defined, you can write the following code:

     lua_Debug ar;
     lua_getglobal(L, "f");  /* get global 'f' */
     lua_getinfo(L, ">S", &ar);
     printf("%d\n", ar.linedefined);

Each character in the string what selects some fields of the structure ar to be filled or a value to be pushed on the stack:

  • 'n': fills in the field name and namewhat;
  • 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
  • 'l': fills in the field currentline;
  • 't': fills in the field istailcall;
  • 'u': fills in the fields nups, nparams, and isvararg;
  • 'f': pushes onto the stack the function that is running at the given level;
  • 'L': pushes onto the stack a table whose indices are the numbers of the lines that are valid on the function. (A valid line is a line with some associated code, that is, a line where you can put a break point. Non-valid lines include empty lines and comments.)

This function returns 0 on error (for instance, an invalid option in what).


lua_getlocal

[-0, +(0|1), –]

const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

Gets information about a local variable of a given activation record or a given function.

In the first case, the parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). The index n selects which local variable to inspect; see debug.getlocal for details about variable indices and names.

lua_getlocal pushes the variable's value onto the stack and returns its name.

In the second case, ar should be NULL and the function to be inspected must be at the top of the stack. In this case, only parameters of Lua functions are visible (as there is no information about what variables are active) and no values are pushed onto the stack.

Returns NULL (and pushes nothing) when the index is greater than the number of active local variables.


lua_getstack

[-0, +0, –]

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

Gets information about the interpreter runtime stack.

This function fills parts of a lua_Debug structure with an identification of the activation record of the function executing at a given level. Level 0 is the current running function, whereas level n+1 is the function that has called level n (except for tail calls, which do not count on the stack). When there are no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0.


lua_getupvalue

[-0, +(0|1), –]

const char *lua_getupvalue (lua_State *L, int funcindex, int n);

Gets information about a closure's upvalue. (For Lua functions, upvalues are the external local variables that the function uses, and that are consequently included in its closure.) lua_getupvalue gets the index n of an upvalue, pushes the upvalue's value onto the stack, and returns its name. funcindex points to the closure in the stack. (Upvalues have no particular order, as they are active through the whole function. So, they are numbered in an arbitrary order.)

Returns NULL (and pushes nothing) when the index is greater than the number of upvalues. For C functions, this function uses the empty string "" as a name for all upvalues.


lua_Hook

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

Type for debugging hook functions.

Whenever a hook is called, its ar argument has its field event set to the specific event that triggered the hook. Lua identifies these events with the following constants: LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, and LUA_HOOKCOUNT. Moreover, for line events, the field currentline is also set. To get the value of any other field in ar, the hook must call lua_getinfo.

For call events, event can be LUA_HOOKCALL, the normal value, or LUA_HOOKTAILCALL, for a tail call; in this case, there will be no corresponding return event.

While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, this execution occurs without any calls to hooks.

Hook functions cannot have continuations, that is, they cannot call lua_yieldk, lua_pcallk, or lua_callk with a non-null k.

Hook functions can yield under the following conditions: Only count and line events can yield and they cannot yield any value; to yield a hook function must finish its execution calling lua_yield with nresults equal to zero.


lua_sethook

[-0, +0, –]

int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

Sets the debugging hook function.

Argument f is the hook function. mask specifies on which events the hook will be called: it is formed by a bitwise or of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, and LUA_MASKCOUNT. The count argument is only meaningful when the mask includes LUA_MASKCOUNT. For each event, the hook is called as explained below:

  • The call hook: is called when the interpreter calls a function. The hook is called just after Lua enters the new function, before the function gets its arguments.
  • The return hook: is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. There is no standard way to access the values to be returned by the function.
  • The line hook: is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.)
  • The count hook: is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.)

A hook is disabled by setting mask to zero.


lua_setlocal

[-(0|1), +0, –]

const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

Sets the value of a local variable of a given activation record. Parameters ar and n are as in lua_getlocal (see lua_getlocal). lua_setlocal assigns the value at the top of the stack to the variable and returns its name. It also pops the value from the stack.

Returns NULL (and pops nothing) when the index is greater than the number of active local variables.


lua_setupvalue

[-(0|1), +0, –]

const char *lua_setupvalue (lua_State *L, int funcindex, int n);

Sets the value of a closure's upvalue. It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. Parameters funcindex and n are as in the lua_getupvalue (see lua_getupvalue).

Returns NULL (and pops nothing) when the index is greater than the number of upvalues.


lua_upvalueid

[-0, +0, –]

void *lua_upvalueid (lua_State *L, int funcindex, int n);

Returns an unique identifier for the upvalue numbered n from the closure at index funcindex. Parameters funcindex and n are as in the lua_getupvalue (see lua_getupvalue) (but n cannot be greater than the number of upvalues).

These unique identifiers allow a program to check whether different closures share upvalues. Lua closures that share an upvalue (that is, that access a same external local variable) will return identical ids for those upvalue indices.


lua_upvaluejoin

[-0, +0, –]

void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                                    int funcindex2, int n2);

Make the n1-th upvalue of the Lua closure at index funcindex1 refer to the n2-th upvalue of the Lua closure at index funcindex2.

5 – The Auxiliary Library

The auxiliary library provides several convenient functions to interface C with Lua. While the basic API provides the primitive functions for all interactions between C and Lua, the auxiliary library provides higher-level functions for some common tasks.

All functions and types from the auxiliary library are defined in header file lauxlib.h and have a prefix luaL_.

All functions in the auxiliary library are built on top of the basic API, and so they provide nothing that cannot be done with that API. Nevertheless, the use of the auxiliary library ensures more consistency to your code.

Several functions in the auxiliary library use internally some extra stack slots. When a function in the auxiliary library uses less than five slots, it does not check the stack size; it simply assumes that there are enough slots.

Several functions in the auxiliary library are used to check C function arguments. Because the error message is formatted for arguments (e.g., "bad argument #1"), you should not use these functions for other stack values.

Functions called luaL_check* always throw an error if the check is not satisfied.

5.1 – Functions and Types

Here we list all functions and types from the auxiliary library in alphabetical order.


luaL_addchar

[-?, +?, e]

void luaL_addchar (luaL_Buffer *B, char c);

Adds the byte c to the buffer B (see luaL_Buffer).


luaL_addlstring

[-?, +?, e]

void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

Adds the string pointed to by s with length l to the buffer B (see luaL_Buffer). The string can contain embedded zeros.


luaL_addsize

[-?, +?, e]

void luaL_addsize (luaL_Buffer *B, size_t n);

Adds to the buffer B (see luaL_Buffer) a string of length n previously copied to the buffer area (see luaL_prepbuffer).


luaL_addstring

[-?, +?, e]

void luaL_addstring (luaL_Buffer *B, const char *s);

Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). The string cannot contain embedded zeros.


luaL_addvalue

[-1, +?, e]

void luaL_addvalue (luaL_Buffer *B);

Adds the value at the top of the stack to the buffer B (see luaL_Buffer). Pops the value.

This is the only function on string buffers that can (and must) be called with an extra element on the stack, which is the value to be added to the buffer.


luaL_argcheck

[-0, +0, v]

void luaL_argcheck (lua_State *L,
                    int cond,
                    int arg,
                    const char *extramsg);

Checks whether cond is true. If not, raises an error with a standard message.


luaL_argerror

[-0, +0, v]

int luaL_argerror (lua_State *L, int arg, const char *extramsg);

Raises an error with a standard message that includes extramsg as a comment.

This function never returns, but it is an idiom to use it in C functions as return luaL_argerror(args).


luaL_Buffer

typedef struct luaL_Buffer luaL_Buffer;

Type for a string buffer.

A string buffer allows C code to build Lua strings piecemeal. Its pattern of use is as follows:

  • First declare a variable b of type luaL_Buffer.
  • Then initialize it with a call luaL_buffinit(L, &b).
  • Then add string pieces to the buffer calling any of the luaL_add* functions.
  • Finish by calling luaL_pushresult(&b). This call leaves the final string on the top of the stack.

If you know beforehand the total size of the resulting string, you can use the buffer like this:

  • First declare a variable b of type luaL_Buffer.
  • Then initialize it and preallocate a space of size sz with a call luaL_buffinitsize(L, &b, sz).
  • Then copy the string into that space.
  • Finish by calling luaL_pushresultsize(&b, sz), where sz is the total size of the resulting string copied into that space.

During its normal operation, a string buffer uses a variable number of stack slots. So, while using a buffer, you cannot assume that you know where the top of the stack is. You can use the stack between successive calls to buffer operations as long as that use is balanced; that is, when you call a buffer operation, the stack is at the same level it was immediately after the previous buffer operation. (The only exception to this rule is luaL_addvalue.) After calling luaL_pushresult the stack is back to its level when the buffer was initialized, plus the final string on its top.


luaL_buffinit

[-0, +0, –]

void luaL_buffinit (lua_State *L, luaL_Buffer *B);

Initializes a buffer B. This function does not allocate any space; the buffer must be declared as a variable (see luaL_Buffer).


luaL_buffinitsize

[-?, +?, e]

char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);

Equivalent to the sequence luaL_buffinit, luaL_prepbuffsize.


luaL_callmeta

[-0, +(0|1), e]

int luaL_callmeta (lua_State *L, int obj, const char *e);

Calls a metamethod.

If the object at index obj has a metatable and this metatable has a field e, this function calls this field passing the object as its only argument. In this case this function returns true and pushes onto the stack the value returned by the call. If there is no metatable or no metamethod, this function returns false (without pushing any value on the stack).


luaL_checkany

[-0, +0, v]

void luaL_checkany (lua_State *L, int arg);

Checks whether the function has an argument of any type (including nil) at position arg.


luaL_checkint

[-0, +0, v]

int luaL_checkint (lua_State *L, int arg);

Checks whether the function argument arg is a number and returns this number cast to an int.


luaL_checkinteger

[-0, +0, v]

lua_Integer luaL_checkinteger (lua_State *L, int arg);

Checks whether the function argument arg is a number and returns this number cast to a lua_Integer.


luaL_checklong

[-0, +0, v]

long luaL_checklong (lua_State *L, int arg);

Checks whether the function argument arg is a number and returns this number cast to a long.


luaL_checklstring

[-0, +0, v]

const char *luaL_checklstring (lua_State *L, int arg, size_t *l);

Checks whether the function argument arg is a string and returns this string; if l is not NULL fills *l with the string's length.

This function uses lua_tolstring to get its result, so all conversions and caveats of that function apply here.


luaL_checknumber

[-0, +0, v]

lua_Number luaL_checknumber (lua_State *L, int arg);

Checks whether the function argument arg is a number and returns this number.


luaL_checkoption

[-0, +0, v]

int luaL_checkoption (lua_State *L,
                      int arg,
                      const char *def,
                      const char *const lst[]);

Checks whether the function argument arg is a string and searches for this string in the array lst (which must be NULL-terminated). Returns the index in the array where the string was found. Raises an error if the argument is not a string or if the string cannot be found.

If def is not NULL, the function uses def as a default value when there is no argument arg or when this argument is nil.

This is a useful function for mapping strings to C enums. (The usual convention in Lua libraries is to use strings instead of numbers to select options.)


luaL_checkstack

[-0, +0, v]

void luaL_checkstack (lua_State *L, int sz, const char *msg);

Grows the stack size to top + sz elements, raising an error if the stack cannot grow to that size. msg is an additional text to go into the error message (or NULL for no additional text).


luaL_checkstring

[-0, +0, v]

const char *luaL_checkstring (lua_State *L, int arg);

Checks whether the function argument arg is a string and returns this string.

This function uses lua_tolstring to get its result, so all conversions and caveats of that function apply here.


luaL_checktype

[-0, +0, v]

void luaL_checktype (lua_State *L, int arg, int t);

Checks whether the function argument arg has type t. See lua_type for the encoding of types for t.


luaL_checkudata

[-0, +0, v]

void *luaL_checkudata (lua_State *L, int arg, const char *tname);

Checks whether the function argument arg is a userdata of the type tname (see luaL_newmetatable) and returns the userdata address (see lua_touserdata).


luaL_checkunsigned

[-0, +0, v]

lua_Unsigned luaL_checkunsigned (lua_State *L, int arg);

Checks whether the function argument arg is a number and returns this number cast to a lua_Unsigned.


luaL_checkversion

[-0, +0, –]

void luaL_checkversion (lua_State *L);

Checks whether the core running the call, the core that created the Lua state, and the code making the call are all using the same version of Lua. Also checks whether the core running the call and the core that created the Lua state are using the same address space.


luaL_dofile

[-0, +?, e]

int luaL_dofile (lua_State *L, const char *filename);

Loads and runs the given file. It is defined as the following macro:

     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

It returns false if there are no errors or true in case of errors.


luaL_dostring

[-0, +?, –]

int luaL_dostring (lua_State *L, const char *str);

Loads and runs the given string. It is defined as the following macro:

     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))

It returns false if there are no errors or true in case of errors.


luaL_error

[-0, +0, v]

int luaL_error (lua_State *L, const char *fmt, ...);

Raises an error. The error message format is given by fmt plus any extra arguments, following the same rules of lua_pushfstring. It also adds at the beginning of the message the file name and the line number where the error occurred, if this information is available.

This function never returns, but it is an idiom to use it in C functions as return luaL_error(args).


luaL_execresult

[-0, +3, e]

int luaL_execresult (lua_State *L, int stat);

This function produces the return values for process-related functions in the standard library (os.execute and io.close).


luaL_fileresult

[-0, +(1|3), e]

int luaL_fileresult (lua_State *L, int stat, const char *fname);

This function produces the return values for file-related functions in the standard library (io.open, os.rename, file:seek, etc.).


luaL_getmetafield

[-0, +(0|1), e]

int luaL_getmetafield (lua_State *L, int obj, const char *e);

Pushes onto the stack the field e from the metatable of the object at index obj. If the object does not have a metatable, or if the metatable does not have this field, returns false and pushes nothing.


luaL_getmetatable

[-0, +1, –]

void luaL_getmetatable (lua_State *L, const char *tname);

Pushes onto the stack the metatable associated with name tname in the registry (see luaL_newmetatable).


luaL_getsubtable

[-0, +1, e]

int luaL_getsubtable (lua_State *L, int idx, const char *fname);

Ensures that the value t[fname], where t is the value at index idx, is a table, and pushes that table onto the stack. Returns true if it finds a previous table there and false if it creates a new table.


luaL_gsub

[-0, +1, e]

const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);

Creates a copy of string s by replacing any occurrence of the string p with the string r. Pushes the resulting string on the stack and returns it.


luaL_len

[-0, +0, e]

int luaL_len (lua_State *L, int index);

Returns the "length" of the value at the given index as a number; it is equivalent to the '#' operator in Lua (see §3.4.6). Raises an error if the result of the operation is not a number. (This case only can happen through metamethods.)


luaL_loadbuffer

[-0, +1, –]

int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);

Equivalent to luaL_loadbufferx with mode equal to NULL.


luaL_loadbufferx

[-0, +1, –]

int luaL_loadbufferx (lua_State *L,
                      const char *buff,
                      size_t sz,
                      const char *name,
                      const char *mode);

Loads a buffer as a Lua chunk. This function uses lua_load to load the chunk in the buffer pointed to by buff with size sz.

This function returns the same results as lua_load. name is the chunk name, used for debug information and error messages. The string mode works as in function lua_load.


luaL_loadfile

[-0, +1, e]

int luaL_loadfile (lua_State *L, const char *filename);

Equivalent to luaL_loadfilex with mode equal to NULL.


luaL_loadfilex

[-0, +1, e]

int luaL_loadfilex (lua_State *L, const char *filename,
                                            const char *mode);

Loads a file as a Lua chunk. This function uses lua_load to load the chunk in the file named filename. If filename is NULL, then it loads from the standard input. The first line in the file is ignored if it starts with a #.

The string mode works as in function lua_load.

This function returns the same results as lua_load, but it has an extra error code LUA_ERRFILE if it cannot open/read the file or the file has a wrong mode.

As lua_load, this function only loads the chunk; it does not run it.


luaL_loadstring

[-0, +1, –]

int luaL_loadstring (lua_State *L, const char *s);

Loads a string as a Lua chunk. This function uses lua_load to load the chunk in the zero-terminated string s.

This function returns the same results as lua_load.

Also as lua_load, this function only loads the chunk; it does not run it.


luaL_newlib

[-0, +1, e]

void luaL_newlib (lua_State *L, const luaL_Reg *l);

Creates a new table and registers there the functions in list l. It is implemented as the following macro:

     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

luaL_newlibtable

[-0, +1, e]

void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

Creates a new table with a size optimized to store all entries in the array l (but does not actually store them). It is intended to be used in conjunction with luaL_setfuncs (see luaL_newlib).

It is implemented as a macro. The array l must be the actual array, not a pointer to it.


luaL_newmetatable

[-0, +1, e]

int luaL_newmetatable (lua_State *L, const char *tname);

If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a metatable for userdata, adds it to the registry with key tname, and returns 1.

In both cases pushes onto the stack the final value associated with tname in the registry.


luaL_newstate

[-0, +0, –]

lua_State *luaL_newstate (void);

Creates a new Lua state. It calls lua_newstate with an allocator based on the standard C realloc function and then sets a panic function (see §4.6) that prints an error message to the standard error output in case of fatal errors.

Returns the new state, or NULL if there is a memory allocation error.


luaL_openlibs

[-0, +0, e]

void luaL_openlibs (lua_State *L);

Opens all standard Lua libraries into the given state.


luaL_optint

[-0, +0, v]

int luaL_optint (lua_State *L, int arg, int d);

If the function argument arg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optinteger

[-0, +0, v]

lua_Integer luaL_optinteger (lua_State *L,
                             int arg,
                             lua_Integer d);

If the function argument arg is a number, returns this number cast to a lua_Integer. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optlong

[-0, +0, v]

long luaL_optlong (lua_State *L, int arg, long d);

If the function argument arg is a number, returns this number cast to a long. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optlstring

[-0, +0, v]

const char *luaL_optlstring (lua_State *L,
                             int arg,
                             const char *d,
                             size_t *l);

If the function argument arg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.

If l is not NULL, fills the position *l with the result's length.


luaL_optnumber

[-0, +0, v]

lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);

If the function argument arg is a number, returns this number. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optstring

[-0, +0, v]

const char *luaL_optstring (lua_State *L,
                            int arg,
                            const char *d);

If the function argument arg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.


luaL_optunsigned

[-0, +0, v]

lua_Unsigned luaL_optunsigned (lua_State *L,
                               int arg,
                               lua_Unsigned u);

If the function argument arg is a number, returns this number cast to a lua_Unsigned. If this argument is absent or is nil, returns u. Otherwise, raises an error.


luaL_prepbuffer

[-?, +?, e]

char *luaL_prepbuffer (luaL_Buffer *B);

Equivalent to luaL_prepbuffsize with the predefined size LUAL_BUFFERSIZE.


luaL_prepbuffsize

[-?, +?, e]

char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);

Returns an address to a space of size sz where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into this space you must call luaL_addsize with the size of the string to actually add it to the buffer.


luaL_pushresult

[-?, +1, e]

void luaL_pushresult (luaL_Buffer *B);

Finishes the use of buffer B leaving the final string on the top of the stack.


luaL_pushresultsize

[-?, +1, e]

void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

Equivalent to the sequence luaL_addsize, luaL_pushresult.


luaL_ref

[-1, +0, e]

int luaL_ref (lua_State *L, int t);

Creates and returns a reference, in the table at index t, for the object at the top of the stack (and pops the object).

A reference is a unique integer key. As long as you do not manually add integer keys into table t, luaL_ref ensures the uniqueness of the key it returns. You can retrieve an object referred by reference r by calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and its associated object.

If the object at the top of the stack is nil, luaL_ref returns the constant LUA_REFNIL. The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref.


luaL_Reg

typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;

Type for arrays of functions to be registered by luaL_setfuncs. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry in which both name and func are NULL.


luaL_requiref

[-0, +1, e]

void luaL_requiref (lua_State *L, const char *modname,
                    lua_CFunction openf, int glb);

Calls function openf with string modname as an argument and sets the call result in package.loaded[modname], as if that function has been called through require.

If glb is true, also stores the result into global modname.

Leaves a copy of that result on the stack.


luaL_setfuncs

[-nup, +0, e]

void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);

Registers all functions in the array l (see luaL_Reg) into the table on the top of the stack (below optional upvalues, see next).

When nup is not zero, all functions are created sharing nup upvalues, which must be previously pushed on the stack on top of the library table. These values are popped from the stack after the registration.


luaL_setmetatable

[-0, +0, –]

void luaL_setmetatable (lua_State *L, const char *tname);

Sets the metatable of the object at the top of the stack as the metatable associated with name tname in the registry (see luaL_newmetatable).


luaL_testudata

[-0, +0, e]

void *luaL_testudata (lua_State *L, int arg, const char *tname);

This function works like luaL_checkudata, except that, when the test fails, it returns NULL instead of throwing an error.


luaL_tolstring

[-0, +1, e]

const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

Converts any Lua value at the given index to a C string in a reasonable format. The resulting string is pushed onto the stack and also returned by the function. If len is not NULL, the function also sets *len with the string length.

If the value has a metatable with a "__tostring" field, then luaL_tolstring calls the corresponding metamethod with the value as argument, and uses the result of the call as its result.


luaL_traceback

[-0, +1, e]

void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                     int level);

Creates and pushes a traceback of the stack L1. If msg is not NULL it is appended at the beginning of the traceback. The level parameter tells at which level to start the traceback.


luaL_typename

[-0, +0, –]

const char *luaL_typename (lua_State *L, int index);

Returns the name of the type of the value at the given index.


luaL_unref

[-0, +0, –]

void luaL_unref (lua_State *L, int t, int ref);

Releases reference ref from the table at index t (see luaL_ref). The entry is removed from the table, so that the referred object can be collected. The reference ref is also freed to be used again.

If ref is LUA_NOREF or LUA_REFNIL, luaL_unref does nothing.


luaL_where

[-0, +1, e]

void luaL_where (lua_State *L, int lvl);

Pushes onto the stack a string identifying the current position of the control at level lvl in the call stack. Typically this string has the following format:

     chunkname:currentline:

Level 0 is the running function, level 1 is the function that called the running function, etc.

This function is used to build a prefix for error messages.

6 – Standard Libraries

The standard Lua libraries provide useful functions that are implemented directly through the C API. Some of these functions provide essential services to the language (e.g., type and getmetatable); others provide access to "outside" services (e.g., I/O); and others could be implemented in Lua itself, but are quite useful or have critical performance requirements that deserve an implementation in C (e.g., table.sort).

All libraries are implemented through the official C API and are provided as separate C modules. Currently, Lua has the following standard libraries:

  • basic library (§6.1);
  • coroutine library (§6.2);
  • package library (§6.3);
  • string manipulation (§6.4);
  • table manipulation (§6.5);
  • mathematical functions (§6.6) (sin, log, etc.);
  • bitwise operations (§6.7);
  • input and output (§6.8);
  • operating system facilities (§6.9);
  • debug facilities (§6.10).

Except for the basic and the package libraries, each library provides all its functions as fields of a global table or as methods of its objects.

To have access to these libraries, the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, the host program can open them individually by using luaL_requiref to call luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_coroutine (for the coroutine library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), luaopen_bit32 (for the bit library), luaopen_io (for the I/O library), luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). These functions are declared in lualib.h.

6.1 – Basic Functions

The basic library provides core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide implementations for some of its facilities.


assert (v [, message])

Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!"


collectgarbage ([opt [, arg]])

This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt:

  • "collect": performs a full garbage-collection cycle. This is the default option.
  • "stop": stops automatic execution of the garbage collector. The collector will run only when explicitly invoked, until a call to restart it.
  • "restart": restarts automatic execution of the garbage collector.
  • "count": returns the total memory in use by Lua (in Kbytes) and a second value with the total memory in bytes modulo 1024. The first value has a fractional part, so the following equality is always true:
         k, b = collectgarbage("count")
         assert(k*1024 == math.floor(k)*1024 + b)
    

    (The second result is useful when Lua is compiled with a non floating-point type for numbers.)

  • "step": performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of arg. Returns true if the step finished a collection cycle.
  • "setpause": sets arg as the new value for the pause of the collector (see §2.5). Returns the previous value for pause.
  • "setstepmul": sets arg as the new value for the step multiplier of the collector (see §2.5). Returns the previous value for step.
  • "isrunning": returns a boolean that tells whether the collector is running (i.e., not stopped).
  • "generational": changes the collector to generational mode. This is an experimental feature (see §2.5).
  • "incremental": changes the collector to incremental mode. This is the default mode.


dofile ([filename])

Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). Returns all values returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode).


error (message [, level])

Terminates the last protected function called and returns message as the error message. Function error never returns.

Usually, error adds some information about the error position at the beginning of the message, if the message is a string. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.


_G

A global variable (not a function) that holds the global environment (see §2.2). Lua itself does not use this variable; changing its value does not affect any environment, nor vice-versa.


getmetatable (object)

If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a "__metatable" field, returns the associated value. Otherwise, returns the metatable of the given object.


ipairs (t)

If t has a metamethod __ipairs, calls it with t as argument and returns the first three results from the call.

Otherwise, returns three values: an iterator function, the table t, and 0, so that the construction

     for i,v in ipairs(t) do body end

will iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key absent from the table.


load (ld [, source [, mode [, env]]])

Loads a chunk.

If ld is a string, the chunk is this string. If ld is a function, load calls it repeatedly to get the chunk pieces. Each call to ld must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.

If there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.

If the resulting function has upvalues, the first upvalue is set to the value of env, if that parameter is given, or to the value of the global environment. (When you load a main chunk, the resulting function will always have exactly one upvalue, the _ENV variable (see §2.2). When you load a binary chunk created from a function (see string.dump), the resulting function can have arbitrary upvalues.)

source is used as the source of the chunk for error messages and debug information (see §4.9). When absent, it defaults to ld, if ld is a string, or to "=(load)" otherwise.

The string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). It may be the string "b" (only binary chunks), "t" (only text chunks), or "bt" (both binary and text). The default is "bt".


loadfile ([filename [, mode [, env]]])

Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.


next (table [, index])

Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table and its associated value. When called with nil as its second argument, next returns an initial index and its associated value. When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, then it is interpreted as nil. In particular, you can use next(t) to check whether a table is empty.

The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for.)

The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.


pairs (t)

If t has a metamethod __pairs, calls it with t as argument and returns the first three results from the call.

Otherwise, returns three values: the next function, the table t, and nil, so that the construction

     for k,v in pairs(t) do body end

will iterate over all key–value pairs of table t.

See function next for the caveats of modifying the table during its traversal.


pcall (f [, arg1, ···])

Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.


print (···)

Receives any number of arguments and prints their values to stdout, using the tostring function to convert each argument to a string. print is not intended for formatted output, but only as a quick way to show a value, for instance for debugging. For complete control over the output, use string.format and io.write.


rawequal (v1, v2)

Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean.


rawget (table, index)

Gets the real value of table[index], without invoking any metamethod. table must be a table; index may be any value.


rawlen (v)

Returns the length of the object v, which must be a table or a string, without invoking any metamethod. Returns an integer number.


rawset (table, index, value)

Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil and NaN, and value any Lua value.

This function returns table.


select (index, ···)

If index is a number, returns all arguments after argument number index; a negative number indexes from the end (-1 is the last argument). Otherwise, index must be the string "#", and select returns the total number of extra arguments it received.


setmetatable (table, metatable)

Sets the metatable for the given table. (You cannot change the metatable of other types from Lua, only from C.) If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, raises an error.

This function returns table.


tonumber (e [, base])

When called with no base, tonumber tries to convert its argument to a number. If the argument is already a number or a string convertible to a number (see §3.4.2), then tonumber returns this number; otherwise, it returns nil.

When called with base, then e should be a string to be interpreted as an integer numeral in that base. The base may be any integer between 2 and 36, inclusive. In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. If the string e is not a valid numeral in the given base, the function returns nil.


tostring (v)

Receives a value of any type and converts it to a string in a reasonable format. (For complete control of how numbers are converted, use string.format.)

If the metatable of v has a "__tostring" field, then tostring calls the corresponding value with v as argument, and uses the result of the call as its result.


type (v)

Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".


_VERSION

A global variable (not a function) that holds a string containing the current interpreter version. The current contents of this variable is "Lua 5.2".


xpcall (f, msgh [, arg1, ···])

This function is similar to pcall, except that it sets a new message handler msgh.

6.2 – Coroutine Manipulation

The operations related to coroutines comprise a sub-library of the basic library and come inside the table coroutine. See §2.6 for a general description of coroutines.


coroutine.create (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread".


coroutine.resume (co [, val1, ···])

Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ... are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ... are passed as the results from the yield.

If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message.


coroutine.running ()

Returns the running coroutine plus a boolean, true when the running coroutine is the main one.


coroutine.status (co)

Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error.


coroutine.wrap (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.


coroutine.yield (···)

Suspends the execution of the calling coroutine. Any arguments to yield are passed as extra results to resume.

6.3 – Modules

The package library provides basic facilities for loading modules in Lua. It exports one function directly in the global environment: require. Everything else is exported in a table package.


require (modname)

Loads the given module. The function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.

To find a loader, require is guided by the package.searchers sequence. By changing this sequence, we can change how require looks for a module. The following explanation is based on the default configuration for package.searchers.

First require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, it tries an all-in-one loader (see package.searchers).

Once a loader is found, require calls the loader with two arguments: modname and an extra value dependent on how it got the loader. (If the loader came from a file, this extra value is the file name.) If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].

If there is any error loading or running the module, or if it cannot find any loader for the module, then require raises an error.


package.config

A string describing some compile-time configurations for packages. This string is a sequence of lines:

  • The first line is the directory separator string. Default is '\' for Windows and '/' for all other systems.
  • The second line is the character that separates templates in a path. Default is ';'.
  • The third line is the string that marks the substitution points in a template. Default is '?'.
  • The fourth line is a string that, in a path in Windows, is replaced by the executable's directory. Default is '!'.
  • The fifth line is a mark to ignore all text before it when building the luaopen_ function name. Default is '-'.


package.cpath

The path used by require to search for a C loader.

Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH_5_2 or the environment variable LUA_CPATH or a default path defined in luaconf.h.


package.loaded

A table used by require to control which modules are already loaded. When you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there.

This variable is only a reference to the real table; assignments to this variable do not change the table used by require.


package.loadlib (libname, funcname)

Dynamically links the host program with the C library libname.

If funcname is "*", then it only links with the library, making the symbols exported by the library available to other dynamically linked libraries. Otherwise, it looks for a function funcname inside the library and returns this function as a C function. So, funcname must follow the lua_CFunction prototype (see lua_CFunction).

This is a low-level function. It completely bypasses the package and module system. Unlike require, it does not perform any path searching and does not automatically adds extensions. libname must be the complete file name of the C library, including if necessary a path and an extension. funcname must be the exact name exported by the C library (which may depend on the C compiler and linker used).

This function is not supported by Standard C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard).


package.path

The path used by require to search for a Lua loader.

At start-up, Lua initializes this variable with the value of the environment variable LUA_PATH_5_2 or the environment variable LUA_PATH or with a default path defined in luaconf.h, if those environment variables are not defined. Any ";;" in the value of the environment variable is replaced by the default path.


package.preload

A table to store loaders for specific modules (see require).

This variable is only a reference to the real table; assignments to this variable do not change the table used by require.


package.searchers

A table used by require to control how to load modules.

Each entry in this table is a searcher function. When looking for a module, require calls each of these searchers in ascending order, with the module name (the argument given to require) as its sole parameter. The function can return another function (the module loader) plus an extra value that will be passed to that loader, or a string explaining why it did not find that module (or nil if it has nothing to say).

Lua initializes this table with four searcher functions.

The first searcher simply looks for a loader in the package.preload table.

The second searcher looks for a loader as a Lua library, using the path stored at package.path. The search is done as described in function package.searchpath.

The third searcher looks for a loader as a C library, using the path given by the variable package.cpath. Again, the search is done as described in function package.searchpath. For instance, if the C path is the string

     "./?.so;./?.dll;/usr/local/?/init.so"

the searcher for module foo will try to open the files ./foo.so, ./foo.dll, and /usr/local/foo/init.so, in that order. Once it finds a C library, this searcher first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside the library to be used as the loader. The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed. For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c.

The fourth searcher tries an all-in-one loader. It searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.

All searchers except the first one (preload) return as the extra value the file name where the module was found, as returned by package.searchpath. The first searcher returns no extra value.


package.searchpath (name, path [, sep [, rep]])

Searches for the given name in the given path.

A path is a string containing a sequence of templates separated by semicolons. For each template, the function replaces each interrogation mark (if any) in the template with a copy of name wherein all occurrences of sep (a dot, by default) were replaced by rep (the system's directory separator, by default), and then tries to open the resulting file name.

For instance, if the path is the string

     "./?.lua;./?.lc;/usr/local/?/init.lua"

the search for the name foo.a will try to open the files ./foo/a.lua, ./foo/a.lc, and /usr/local/foo/a/init.lua, in that order.

Returns the resulting name of the first file that it can open in read mode (after closing the file), or nil plus an error message if none succeeds. (This error message lists all file names it tried to open.)

6.4 – String Manipulation

This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. When indexing a string in Lua, the first character is at position 1 (not at 0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.

The string library provides all its functions inside the table string. It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s,i) can be written as s:byte(i).

The string library assumes one-byte character encodings.


string.byte (s [, i [, j]])

Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i. These indices are corrected following the same rules of function string.sub.

Numerical codes are not necessarily portable across platforms.


string.char (···)

Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument.

Numerical codes are not necessarily portable across platforms.


string.dump (function)

Returns a string containing a binary representation of the given function, so that a later load on this string returns a copy of the function (but with new upvalues).


string.find (s, pattern [, init [, plain]])

Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered magic. Note that if plain is given, then init must be given as well.

If the pattern has captures, then in a successful match the captured values are also returned, after the two indices.


string.format (formatstring, ···)

Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the ANSI C function sprintf. The only differences are that the options/modifiers *, h, L, l, n, and p are not supported and that there is an extra option, q. The q option formats a string between double quotes, using escape sequences when necessary to ensure that it can safely be read back by the Lua interpreter. For instance, the call

     string.format('%q', 'a string with "quotes" and \n new line')

may produce the string:

     "a string with \"quotes\" and \
      new line"

Options A and a (when available), E, e, f, G, and g all expect a number as argument. Options c, d, i, o, u, X, and x also expect a number, but the range of that number may be limited by the underlying C implementation. For options o, u, X, and x, the number cannot be negative. Option q expects a string; option s expects a string without embedded zeros. If the argument to option s is not a string, it is converted to one following the same rules of tostring.


string.gmatch (s, pattern)

Returns an iterator function that, each time it is called, returns the next captures from pattern over the string s. If pattern specifies no captures, then the whole match is produced in each call.

As an example, the following loop will iterate over all the words from string s, printing one per line:

     s = "hello world from Lua"
     for w in string.gmatch(s, "%a+") do
       print(w)
     end

The next example collects all pairs key=value from the given string into a table:

     t = {}
     s = "from=world, to=Lua"
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end

For this function, a caret '^' at the start of a pattern does not work as an anchor, as this would prevent the iteration.


string.gsub (s, pattern, repl [, n])

Returns a copy of s in which all (or the first n, if given) occurrences of the pattern have been replaced by a replacement string specified by repl, which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred. The name gsub comes from Global SUBstitution.

If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %d, with d between 1 and 9, stands for the value of the d-th captured substring. The sequence %0 stands for the whole match. The sequence %% stands for a single %.

If repl is a table, then the table is queried for every match, using the first capture as the key.

If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order.

In any case, if the pattern specifies no captures, then it behaves as if the whole pattern was inside a capture.

If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string).

Here are some examples:

     x = string.gsub("hello world", "(%w+)", "%1 %1")
     --> x="hello hello world world"
     
     x = string.gsub("hello world", "%w+", "%0 %0", 1)
     --> x="hello hello world"
     
     x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
     --> x="world hello Lua from"
     
     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
     --> x="home = /home/roberto, user = roberto"
     
     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
           return load(s)()
         end)
     --> x="4+5 = 9"
     
     local t = {name="lua", version="5.2"}
     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
     --> x="lua-5.2.tar.gz"


string.len (s)

Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5.


string.lower (s)

Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale.


string.match (s, pattern [, init])

Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative.


string.rep (s, n [, sep])

Returns a string that is the concatenation of n copies of the string s separated by the string sep. The default value for sep is the empty string (that is, no separator).


string.reverse (s)

Returns a string that is the string s reversed.


string.sub (s, i [, j])

Returns the substring of s that starts at i and continues until j; i and j can be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.

If, after the translation of negative indices, i is less than 1, it is corrected to 1. If j is greater than the string length, it is corrected to that length. If, after these corrections, i is greater than j, the function returns the empty string.


string.upper (s)

Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale.

6.4.1 – Patterns

Character Class:

A character class is used to represent a set of characters. The following combinations are allowed in describing a character class:

  • x: (where x is not one of the magic characters ^$()%.[]*+-?) represents the character x itself.
  • .: (a dot) represents all characters.
  • %a: represents all letters.
  • %c: represents all control characters.
  • %d: represents all digits.
  • %g: represents all printable characters except space.
  • %l: represents all lowercase letters.
  • %p: represents all punctuation characters.
  • %s: represents all space characters.
  • %u: represents all uppercase letters.
  • %w: represents all alphanumeric characters.
  • %x: represents all hexadecimal digits.
  • %x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) can be preceded by a '%' when used to represent itself in a pattern.
  • [set]: represents the class which is the union of all characters in set. A range of characters can be specified by separating the end characters of the range, in ascending order, with a '-', All classes %x described above can also be used as components in set. All other characters in set represent themselves. For example, [%w_] (or [_%w]) represents all alphanumeric characters plus the underscore, [0-7] represents the octal digits, and [0-7%l%-] represents the octal digits plus the lowercase letters plus the '-' character.

    The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning.

  • [^set]: represents the complement of set, where set is interpreted as above.

For all classes represented by single letters (%a, %c, etc.), the corresponding uppercase letter represents the complement of the class. For instance, %S represents all non-space characters.

The definitions of letter, space, and other character groups depend on the current locale. In particular, the class [a-z] may not be equivalent to %l.

Pattern Item:

A pattern item can be

  • a single character class, which matches any single character in the class;
  • a single character class followed by '*', which matches 0 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
  • a single character class followed by '+', which matches 1 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
  • a single character class followed by '-', which also matches 0 or more repetitions of characters in the class. Unlike '*', these repetition items will always match the shortest possible sequence;
  • a single character class followed by '?', which matches 0 or 1 occurrence of a character in the class;
  • %n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below);
  • %bxy, where x and y are two distinct characters; such item matches strings that start with x, end with y, and where the x and y are balanced. This means that, if one reads the string from left to right, counting +1 for an x and -1 for a y, the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses.
  • %f[set], a frontier pattern; such item matches an empty string at any position such that the next character belongs to set and the previous character does not belong to set. The set set is interpreted as previously described. The beginning and the end of the subject are handled as if they were the character '\0'.

Pattern:

A pattern is a sequence of pattern items. A caret '^' at the beginning of a pattern anchors the match at the beginning of the subject string. A '$' at the end of a pattern anchors the match at the end of the subject string. At other positions, '^' and '$' have no special meaning and represent themselves.

Captures:

A pattern can contain sub-patterns enclosed in parentheses; they describe captures. When a match succeeds, the substrings of the subject string that match captures are stored (captured) for future use. Captures are numbered according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is stored as the first capture (and therefore has number 1); the character matching "." is captured with number 2, and the part matching "%s*" has number 3.

As a special case, the empty capture () captures the current string position (a number). For instance, if we apply the pattern "()aa()" on the string "flaaap", there will be two captures: 3 and 5.

6.5 – Table Manipulation

This library provides generic functions for table manipulation. It provides all its functions inside the table table.

Remember that, whenever an operation needs the length of a table, the table should be a proper sequence or have a __len metamethod (see §3.4.6). All functions ignore non-numeric keys in tables given as arguments.

For performance reasons, all table accesses (get/set) performed by these functions are raw.


table.concat (list [, sep [, i [, j]]])

Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string.


table.insert (list, [pos,] value)

Inserts element value at position pos in list, shifting up the elements list[pos], list[pos+1], ···, list[#list]. The default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end of list t.


table.pack (···)

Returns a new table with all parameters stored into keys 1, 2, etc. and with a field "n" with the total number of parameters. Note that the resulting table may not be a sequence.


table.remove (list [, pos])

Removes from list the element at position pos, returning the value of the removed element. When pos is an integer between 1 and #list, it shifts down the elements list[pos+1], list[pos+2], ···, list[#list] and erases element list[#list]; The index pos can also be 0 when #list is 0, or #list + 1; in those cases, the function erases the element list[pos].

The default value for pos is #list, so that a call table.remove(t) removes the last element of list t.


table.sort (list [, comp])

Sorts list elements in a given order, in-place, from list[1] to list[#list]. If comp is given, then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order (so that not comp(list[i+1],list[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead.

The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.


table.unpack (list [, i [, j]])

Returns the elements from the given table. This function is equivalent to

     return list[i], list[i+1], ···, list[j]

By default, i is 1 and j is #list.

6.6 – Mathematical Functions

This library is an interface to the standard C math library. It provides all its functions inside the table math.


math.abs (x)

Returns the absolute value of x.


math.acos (x)

Returns the arc cosine of x (in radians).


math.asin (x)

Returns the arc sine of x (in radians).


math.atan (x)

Returns the arc tangent of x (in radians).


math.atan2 (y, x)

Returns the arc tangent of y/x (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of x being zero.)


math.ceil (x)

Returns the smallest integer larger than or equal to x.


math.cos (x)

Returns the cosine of x (assumed to be in radians).


math.cosh (x)

Returns the hyperbolic cosine of x.


math.deg (x)

Returns the angle x (given in radians) in degrees.


math.exp (x)

Returns the value ex.


math.floor (x)

Returns the largest integer smaller than or equal to x.


math.fmod (x, y)

Returns the remainder of the division of x by y that rounds the quotient towards zero.


math.frexp (x)

Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).


math.huge

The value HUGE_VAL, a value larger than or equal to any other numerical value.


math.ldexp (m, e)

Returns m2e (e should be an integer).


math.log (x [, base])

Returns the logarithm of x in the given base. The default for base is e (so that the function returns the natural logarithm of x).


math.max (x, ···)

Returns the maximum value among its arguments.


math.min (x, ···)

Returns the minimum value among its arguments.


math.modf (x)

Returns two numbers, the integral part of x and the fractional part of x.


math.pi

The value of π.


math.pow (x, y)

Returns xy. (You can also use the expression x^y to compute this value.)


math.rad (x)

Returns the angle x (given in degrees) in radians.


math.random ([m [, n]])

This function is an interface to the simple pseudo-random generator function rand provided by Standard C. (No guarantees can be given for its statistical properties.)

When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n].


math.randomseed (x)

Sets x as the "seed" for the pseudo-random generator: equal seeds produce equal sequences of numbers.


math.sin (x)

Returns the sine of x (assumed to be in radians).


math.sinh (x)

Returns the hyperbolic sine of x.


math.sqrt (x)

Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)


math.tan (x)

Returns the tangent of x (assumed to be in radians).


math.tanh (x)

Returns the hyperbolic tangent of x.

6.7 – Bitwise Operations

This library provides bitwise operations. It provides all its functions inside the table bit32.

Unless otherwise stated, all functions accept numeric arguments in the range (-251,+251); each argument is normalized to the remainder of its division by 232 and truncated to an integer (in some unspecified way), so that its final value falls in the range [0,232 - 1]. Similarly, all results are in the range [0,232 - 1]. Note that bit32.bnot(0) is 0xFFFFFFFF, which is different from -1.


bit32.arshift (x, disp)

Returns the number x shifted disp bits to the right. The number disp may be any representable integer. Negative displacements shift to the left.

This shift operation is what is called arithmetic shift. Vacant bits on the left are filled with copies of the higher bit of x; vacant bits on the right are filled with zeros. In particular, displacements with absolute values higher than 31 result in zero or 0xFFFFFFFF (all original bits are shifted out).


bit32.band (···)

Returns the bitwise and of its operands.


bit32.bnot (x)

Returns the bitwise negation of x. For any integer x, the following identity holds:

     assert(bit32.bnot(x) == (-1 - x) % 2^32)


bit32.bor (···)

Returns the bitwise or of its operands.


bit32.btest (···)

Returns a boolean signaling whether the bitwise and of its operands is different from zero.


bit32.bxor (···)

Returns the bitwise exclusive or of its operands.


bit32.extract (n, field [, width])

Returns the unsigned number formed by the bits field to field + width - 1 from n. Bits are numbered from 0 (least significant) to 31 (most significant). All accessed bits must be in the range [0, 31].

The default for width is 1.


bit32.replace (n, v, field [, width])

Returns a copy of n with the bits field to field + width - 1 replaced by the value v. See bit32.extract for details about field and width.


bit32.lrotate (x, disp)

Returns the number x rotated disp bits to the left. The number disp may be any representable integer.

For any valid displacement, the following identity holds:

     assert(bit32.lrotate(x, disp) == bit32.lrotate(x, disp % 32))

In particular, negative displacements rotate to the right.


bit32.lshift (x, disp)

Returns the number x shifted disp bits to the left. The number disp may be any representable integer. Negative displacements shift to the right. In any direction, vacant bits are filled with zeros. In particular, displacements with absolute values higher than 31 result in zero (all bits are shifted out).

For positive displacements, the following equality holds:

     assert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32)


bit32.rrotate (x, disp)

Returns the number x rotated disp bits to the right. The number disp may be any representable integer.

For any valid displacement, the following identity holds:

     assert(bit32.rrotate(x, disp) == bit32.rrotate(x, disp % 32))

In particular, negative displacements rotate to the left.


bit32.rshift (x, disp)

Returns the number x shifted disp bits to the right. The number disp may be any representable integer. Negative displacements shift to the left. In any direction, vacant bits are filled with zeros. In particular, displacements with absolute values higher than 31 result in zero (all bits are shifted out).

For positive displacements, the following equality holds:

     assert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))

This shift operation is what is called logical shift.

6.8 – Input and Output Facilities

The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors.

When using implicit file descriptors, all operations are supplied by table io. When using explicit file descriptors, the operation io.open returns a file descriptor and then all operations are supplied as methods of the file descriptor.

The table io also provides three predefined file descriptors with their usual meanings from C: io.stdin, io.stdout, and io.stderr. The I/O library never closes these files.

Unless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success. On non-Posix systems, the computation of the error message and error code in case of errors may be not thread safe, because they rely on the global C variable errno.


io.close ([file])

Equivalent to file:close(). Without a file, closes the default output file.


io.flush ()

Equivalent to io.output():flush().


io.input ([file])

When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file.

In case of errors this function raises the error, instead of returning an error code.


io.lines ([filename ···])

Opens the given file name in read mode and returns an iterator function that works like file:lines(···) over the opened file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file.

The call io.lines() (with no file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. In this case it does not close the file when the loop ends.

In case of errors this function raises the error, instead of returning an error code.


io.open (filename [, mode])

This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message.

The mode string can be any of the following:

  • "r": read mode (the default);
  • "w": write mode;
  • "a": append mode;
  • "r+": update mode, all previous data is preserved;
  • "w+": update mode, all previous data is erased;
  • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

The mode string can also have a 'b' at the end, which is needed in some systems to open the file in binary mode.


io.output ([file])

Similar to io.input, but operates over the default output file.


io.popen (prog [, mode])

This function is system dependent and is not available on all platforms.

Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w").


io.read (···)

Equivalent to io.input():read(···).


io.tmpfile ()

Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends.


io.type (obj)

Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle.


io.write (···)

Equivalent to io.output():write(···).


file:close ()

Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.

When closing a file handle created with io.popen, file:close returns the same values returned by os.execute.


file:flush ()

Saves any written data to file.


file:lines (···)

Returns an iterator function that, each time it is called, reads the file according to the given formats. When no format is given, uses "*l" as a default. As an example, the construction

     for c in file:lines(1) do body end

will iterate over all characters of the file, starting at the current position. Unlike io.lines, this function does not close the file when the loop ends.

In case of errors this function raises the error, instead of returning an error code.


file:read (···)

Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the next line (see below).

The available formats are

  • "*n": reads a number; this is the only format that returns a number instead of a string.
  • "*a": reads the whole file, starting at the current position. On end of file, it returns the empty string.
  • "*l": reads the next line skipping the end of line, returning nil on end of file. This is the default format.
  • "*L": reads the next line keeping the end of line (if present), returning nil on end of file.
  • number: reads a string with up to this number of bytes, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file.


file:seek ([whence [, offset]])

Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:

  • "set": base is position 0 (beginning of the file);
  • "cur": base is current position;
  • "end": base is end of file;

In case of success, seek returns the final file position, measured in bytes from the beginning of the file. If seek fails, it returns nil, plus a string describing the error.

The default value for whence is "cur", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; the call file:seek("set") sets the position to the beginning of the file (and returns 0); and the call file:seek("end") sets the position to the end of the file, and returns its size.


file:setvbuf (mode [, size])

Sets the buffering mode for an output file. There are three available modes:

  • "no": no buffering; the result of any output operation appears immediately.
  • "full": full buffering; output operation is performed only when the buffer is full or when you explicitly flush the file (see io.flush).
  • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device).

For the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size.


file:write (···)

Writes the value of each of its arguments to file. The arguments must be strings or numbers.

In case of success, this function returns file. Otherwise it returns nil plus a string describing the error.

6.9 – Operating System Facilities

This library is implemented through table os.


os.clock ()

Returns an approximation of the amount in seconds of CPU time used by the program.


os.date ([format [, time]])

Returns a string or a table containing date and time, formatted according to the given string format.

If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.

If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year (four digits), month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61), wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available.

If format is not "*t", then date returns the date as a string, formatted according to the same rules as the ANSI C function strftime.

When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")).

On non-Posix systems, this function may be not thread safe because of its reliance on C function gmtime and C function localtime.


os.difftime (t2, t1)

Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1.


os.execute ([command])

This function is equivalent to the ANSI C function system. It passes command to be executed by an operating system shell. Its first result is true if the command terminated successfully, or nil otherwise. After this first result the function returns a string and a number, as follows:

  • "exit": the command terminated normally; the following number is the exit status of the command.
  • "signal": the command was terminated by a signal; the following number is the signal that terminated the command.

When called without a command, os.execute returns a boolean that is true if a shell is available.


os.exit ([code [, close])

Calls the ANSI C function exit to terminate the host program. If code is true, the returned status is EXIT_SUCCESS; if code is false, the returned status is EXIT_FAILURE; if code is a number, the returned status is this number. The default value for code is true.

If the optional second argument close is true, closes the Lua state before exiting.


os.getenv (varname)

Returns the value of the process environment variable varname, or nil if the variable is not defined.


os.remove (filename)

Deletes the file (or empty directory, on POSIX systems) with the given name. If this function fails, it returns nil, plus a string describing the error and the error code.


os.rename (oldname, newname)

Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error and the error code.


os.setlocale (locale [, category])

Sets the current locale of the program. locale is a system-dependent string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored.

If locale is the empty string, the current locale is set to an implementation-defined native locale. If locale is the string "C", the current locale is set to the standard C locale.

When called with nil as the first argument, this function only returns the name of the current locale for the given category.

This function may be not thread safe because of its reliance on C function setlocale.


os.time ([table])

Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour (default is 12), min (default is 0), sec (default is 0), and isdst (default is nil). For a description of these fields, see the os.date function.

The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to os.date and os.difftime.


os.tmpname ()

Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed.

On POSIX systems, this function also creates a file with that name, to avoid security risks. (Someone else might create the file with wrong permissions in the time between getting the name and creating the file.) You still have to open the file to use it and to remove it (even if you do not use it).

When possible, you may prefer to use io.tmpfile, which automatically removes the file when the program ends.

6.10 – The Debug Library

This library provides the functionality of the debug interface (§4.9) to Lua programs. You should exert care when using this library. Several of its functions violate basic assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside; that userdata metatables cannot be changed by Lua code; that Lua programs do not crash) and therefore can compromise otherwise secure code. Moreover, some functions in this library may be slow.

All functions in this library are provided inside the debug table. All functions that operate over a thread have an optional first argument which is the thread to operate over. The default is always the current thread.


debug.debug ()

Enters an interactive mode with the user, running each string that the user enters. Using simple commands and other debug facilities, the user can inspect global and local variables, change their values, evaluate expressions, and so on. A line containing only the word cont finishes this function, so that the caller continues its execution.

Note that commands for debug.debug are not lexically nested within any function and so have no direct access to local variables.


debug.gethook ([thread])

Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function).


debug.getinfo ([thread,] f [, what])

Returns a table with information about a function. You can give the function directly or you can give a number as the value of f, which means the function running at level f of the call stack of the given thread: level 0 is the current function (getinfo itself); level 1 is the function that called getinfo (except for tail calls, which do not count on the stack); and so on. If f is a number larger than the number of active functions, then getinfo returns nil.

The returned table can contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available, except the table of valid lines. If present, the option 'f' adds a field named func with the function itself. If present, the option 'L' adds a field named activelines with the table of valid lines.

For instance, the expression debug.getinfo(1,"n").name returns a table with a name for the current function, if a reasonable name can be found, and the expression debug.getinfo(print) returns a table with all available information about the print function.


debug.getlocal ([thread,] f, local)

This function returns the name and the value of the local variable with index local of the function at level f of the stack. This function accesses not only explicit local variables, but also parameters, temporaries, etc.

The first parameter or local variable has index 1, and so on, until the last active variable. Negative indices refer to vararg parameters; -1 is the first vararg parameter. The function returns nil if there is no variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.)

Variable names starting with '(' (open parenthesis) represent internal variables (loop control variables, temporaries, varargs, and C function locals).

The parameter f may also be a function. In that case, getlocal returns only the name of function parameters.


debug.getmetatable (value)

Returns the metatable of the given value or nil if it does not have a metatable.


debug.getregistry ()

Returns the registry table (see §4.5).


debug.getupvalue (f, up)

This function returns the name and the value of the upvalue with index up of the function f. The function returns nil if there is no upvalue with the given index.


debug.getuservalue (u)

Returns the Lua value associated to u. If u is not a userdata, returns nil.


debug.sethook ([thread,] hook, mask [, count])

Sets the given function as a hook. The string mask and the number count describe when the hook will be called. The string mask may have the following characters, with the given meaning:

  • 'c': the hook is called every time Lua calls a function;
  • 'r': the hook is called every time Lua returns from a function;
  • 'l': the hook is called every time Lua enters a new line of code.

With a count different from zero, the hook is called after every count instructions.

When called without arguments, debug.sethook turns off the hook.

When the hook is called, its first parameter is a string describing the event that has triggered its call: "call" (or "tail call"), "return", "line", and "count". For line events, the hook also gets the new line number as its second parameter. Inside a hook, you can call getinfo with level 2 to get more information about the running function (level 0 is the getinfo function, and level 1 is the hook function).


debug.setlocal ([thread,] level, local, value)

This function assigns the value value to the local variable with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable.

See debug.getlocal for more information about variable indices and names.


debug.setmetatable (value, table)

Sets the metatable for the given value to the given table (which can be nil). Returns value.


debug.setupvalue (f, up, value)

This function assigns the value value to the upvalue with index up of the function f. The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue.


debug.setuservalue (udata, value)

Sets the given value as the Lua value associated to the given udata. value must be a table or nil; udata must be a full userdata.

Returns udata.


debug.traceback ([thread,] [message [, level]])

If message is present but is neither a string nor nil, this function returns message without further processing. Otherwise, it returns a string with a traceback of the call stack. An optional message string is appended at the beginning of the traceback. An optional level number tells at which level to start the traceback (default is 1, the function calling traceback).


debug.upvalueid (f, n)

Returns an unique identifier (as a light userdata) for the upvalue numbered n from the given function.

These unique identifiers allow a program to check whether different closures share upvalues. Lua closures that share an upvalue (that is, that access a same external local variable) will return identical ids for those upvalue indices.


debug.upvaluejoin (f1, n1, f2, n2)

Make the n1-th upvalue of the Lua closure f1 refer to the n2-th upvalue of the Lua closure f2.

7 – Lua Standalone

Although Lua has been designed as an extension language, to be embedded in a host C program, it is also frequently used as a standalone language. An interpreter for Lua as a standalone language, called simply lua, is provided with the standard distribution. The standalone interpreter includes all standard libraries, including the debug library. Its usage is:

     lua [options] [script [args]]

The options are:

  • -e stat: executes string stat;
  • -l mod: "requires" mod;
  • -i: enters interactive mode after running script;
  • -v: prints version information;
  • -E: ignores environment variables;
  • --: stops handling options;
  • -: executes stdin as a file and stops handling options.

After handling its options, lua runs the given script, passing to it the given args as string arguments. When called without arguments, lua behaves as lua -v -i when the standard input (stdin) is a terminal, and as lua - otherwise.

When called without option -E, the interpreter checks for an environment variable LUA_INIT_5_2 (or LUA_INIT if it is not defined) before running any argument. If the variable content has the format @filename, then lua executes the file. Otherwise, lua executes the string itself.

When called with option -E, besides ignoring LUA_INIT, Lua also ignores the values of LUA_PATH and LUA_CPATH, setting the values of package.path and package.cpath with the default paths defined in luaconf.h.

All options are handled in order, except -i and -E. For instance, an invocation like

     $ lua -e'a=1' -e 'print(a)' script.lua

will first set a to 1, then print the value of a, and finally run the file script.lua with no arguments. (Here $ is the shell prompt. Your prompt may be different.)

Before starting to run the script, lua collects all arguments in the command line in a global table called arg. The script name is stored at index 0, the first argument after the script name goes to index 1, and so on. Any arguments before the script name (that is, the interpreter name plus the options) go to negative indices. For instance, in the call

     $ lua -la b.lua t1 t2

the interpreter first runs the file a.lua, then creates a table

     arg = { [-2] = "lua", [-1] = "-la",
             [0] = "b.lua",
             [1] = "t1", [2] = "t2" }

and finally runs the file b.lua. The script is called with arg[1], arg[2], ... as arguments; it can also access these arguments with the vararg expression '...'.

In interactive mode, if you write an incomplete statement, the interpreter waits for its completion by issuing a different prompt.

In case of unprotected errors in the script, the interpreter reports the error to the standard error stream. If the error object is a string, the interpreter adds a stack traceback to it. Otherwise, if the error object has a metamethod __tostring, the interpreter calls this metamethod to produce the final message. Finally, if the error object is nil, the interpreter does not report the error.

When finishing normally, the interpreter closes its main Lua state (see lua_close). The script can avoid this step by calling os.exit to terminate.

To allow the use of Lua as a script interpreter in Unix systems, the standalone interpreter skips the first line of a chunk if it starts with #. Therefore, Lua scripts can be made into executable programs by using chmod +x and the #! form, as in

     #!/usr/local/bin/lua

(Of course, the location of the Lua interpreter may be different in your machine. If lua is in your PATH, then

     #!/usr/bin/env lua

is a more portable solution.)

8 – Incompatibilities with the Previous Version

Here we list the incompatibilities that you may find when moving a program from Lua 5.1 to Lua 5.2. You can avoid some incompatibilities by compiling Lua with appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua. Similarly, all features marked as deprecated in Lua 5.1 have been removed in Lua 5.2.

8.1 – Changes in the Language

  • The concept of environment changed. Only Lua functions have environments. To set the environment of a Lua function, use the variable _ENV or the function load.

    C functions no longer have environments. Use an upvalue with a shared table if you need to keep shared state among several C functions. (You may use luaL_setfuncs to open a C library with all functions sharing a common upvalue.)

    To manipulate the "environment" of a userdata (which is now called user value), use the new functions lua_getuservalue and lua_setuservalue.

  • Lua identifiers cannot use locale-dependent letters.
  • Doing a step or a full collection in the garbage collector does not restart the collector if it has been stopped.
  • Weak tables with weak keys now perform like ephemeron tables.
  • The event tail return in debug hooks was removed. Instead, tail calls generate a special new event, tail call, so that the debugger can know that there will not be a corresponding return event.
  • Equality between function values has changed. Now, a function definition may not create a new value; it may reuse some previous value if there is no observable difference to the new function.

8.2 – Changes in the Libraries

  • Function module is deprecated. It is easy to set up a module with regular Lua code. Modules are not expected to set global variables.
  • Functions setfenv and getfenv were removed, because of the changes in environments.
  • Function math.log10 is deprecated. Use math.log with 10 as its second argument, instead.
  • Function loadstring is deprecated. Use load instead; it now accepts string arguments and are exactly equivalent to loadstring.
  • Function table.maxn is deprecated. Write it in Lua if you really need it.
  • Function os.execute now returns true when command terminates successfully and nil plus error information otherwise.
  • Function unpack was moved into the table library and therefore must be called as table.unpack.
  • Character class %z in patterns is deprecated, as now patterns may contain '\0' as a regular character.
  • The table package.loaders was renamed package.searchers.
  • Lua does not have bytecode verification anymore. So, all functions that load code (load and loadfile) are potentially insecure when loading untrusted binary data. (Actually, those functions were already insecure because of flaws in the verification algorithm.) When in doubt, use the mode argument of those functions to restrict them to loading textual chunks.
  • The standard paths in the official distribution may change between versions.

8.3 – Changes in the API

  • Pseudoindex LUA_GLOBALSINDEX was removed. You must get the global environment from the registry (see §4.5).
  • Pseudoindex LUA_ENVIRONINDEX and functions lua_getfenv/lua_setfenv were removed, as C functions no longer have environments.
  • Function luaL_register is deprecated. Use luaL_setfuncs so that your module does not create globals. (Modules are not expected to set global variables anymore.)
  • The osize argument to the allocation function may not be zero when creating a new block, that is, when ptr is NULL (see lua_Alloc). Use only the test ptr == NULL to check whether the block is new.
  • Finalizers (__gc metamethods) for userdata are called in the reverse order that they were marked for finalization, not that they were created (see §2.5.1). (Most userdata are marked immediately after they are created.) Moreover, if the metatable does not have a __gc field when set, the finalizer will not be called, even if it is set later.
  • luaL_typerror was removed. Write your own version if you need it.
  • Function lua_cpcall is deprecated. You can simply push the function with lua_pushcfunction and call it with lua_pcall.
  • Functions lua_equal and lua_lessthan are deprecated. Use the new lua_compare with appropriate options instead.
  • Function lua_objlen was renamed lua_rawlen.
  • Function lua_load has an extra parameter, mode. Pass NULL to simulate the old behavior.
  • Function lua_resume has an extra parameter, from. Pass NULL or the thread doing the call.

9 – The Complete Syntax of Lua

Here is the complete syntax of Lua in extended BNF. (It does not describe operator precedences.)


	chunk ::= block

	block ::= {stat} [retstat]

	stat ::=  ‘;’ | 
		 varlist ‘=’ explist | 
		 functioncall | 
		 label | 
		 break | 
		 goto Name | 
		 do block end | 
		 while exp do block end | 
		 repeat block until exp | 
		 if exp then block {elseif exp then block} [else block] end | 
		 for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | 
		 for namelist in explist do block end | 
		 function funcname funcbody | 
		 local function Name funcbody | 
		 local namelist [‘=’ explist] 

	retstat ::= return [explist] [‘;’]

	label ::= ‘::’ Name ‘::’

	funcname ::= Name {‘.’ Name} [‘:’ Name]

	varlist ::= var {‘,’ var}

	var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 

	namelist ::= Name {‘,’ Name}

	explist ::= exp {‘,’ exp}

	exp ::=  nil | false | true | Number | String | ‘...’ | functiondef | 
		 prefixexp | tableconstructor | exp binop exp | unop exp 

	prefixexp ::= var | functioncall | ‘(’ exp ‘)’

	functioncall ::=  prefixexp args | prefixexp ‘:’ Name args 

	args ::=  ‘(’ [explist] ‘)’ | tableconstructor | String 

	functiondef ::= function funcbody

	funcbody ::= ‘(’ [parlist] ‘)’ block end

	parlist ::= namelist [‘,’ ‘...’] | ‘...’

	tableconstructor ::= ‘{’ [fieldlist] ‘}’

	fieldlist ::= field {fieldsep field} [fieldsep]

	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp

	fieldsep ::= ‘,’ | ‘;’

	binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘^’ | ‘%’ | ‘..’ | 
		 ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 
		 and | or

	unop ::= ‘-’ | not | ‘#


Last update: Thu Mar 21 12:58:59 BRT 2013 OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/luac.10000644000175000017500000000577713151044751025603 0ustar albertoalberto.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $ .TH LUAC 1 "$Date: 2011/11/16 13:53:40 $" .SH NAME luac \- Lua compiler .SH SYNOPSIS .B luac [ .I options ] [ .I filenames ] .SH DESCRIPTION .B luac is the Lua compiler. It translates programs written in the Lua programming language into binary files containing precompiled chunks that can be later loaded and executed. .LP The main advantages of precompiling chunks are: faster loading, protecting source code from accidental user changes, and off-line syntax checking. Precompiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. .B luac simply allows those bytecodes to be saved in a file for later execution. Precompiled chunks are not necessarily smaller than the corresponding source. The main goal in precompiling is faster loading. .LP In the command line, you can mix text files containing Lua source and binary files containing precompiled chunks. .B luac produces a single output file containing the combined bytecodes for all files given. Executing the combined file is equivalent to executing the given files. By default, the output file is named .BR luac.out , but you can change this with the .B \-o option. .LP Precompiled chunks are .I not portable across different architectures. Moreover, the internal format of precompiled chunks is likely to change when a new version of Lua is released. Make sure you save the source files of all Lua programs that you precompile. .LP .SH OPTIONS .TP .B \-l produce a listing of the compiled bytecode for Lua's virtual machine. Listing bytecodes is useful to learn about Lua's virtual machine. If no files are given, then .B luac loads .B luac.out and lists its contents. Use .B \-l \-l for a full listing. .TP .BI \-o " file" output to .IR file , instead of the default .BR luac.out . (You can use .B "'\-'" for standard output, but not on platforms that open standard output in text mode.) The output file may be one of the given files because all files are loaded before the output file is written. Be careful not to overwrite precious files. .TP .B \-p load files but do not generate any output file. Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. If no files are given, then .B luac loads .B luac.out and tests its contents. No messages are displayed if the file loads without errors. .TP .B \-s strip debug information before writing the output file. This saves some space in very large chunks, but if errors occur when running a stripped chunk, then the error messages may not contain the full information they usually do. In particular, line numbers and names of local variables are lost. .TP .B \-v show version information. .TP .B \-\- stop handling options. .TP .B \- stop handling options and process standard input. .SH "SEE ALSO" .BR lua (1) .br The documentation at lua.org. .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS R. Ierusalimschy, L. H. de Figueiredo, W. Celes .\" EOF OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/lua-5.2.3/doc/logo.gif0000644000175000017500000001021013151044751026176 0ustar albertoalbertoGIF87arvz}~ oooqqqvvvzzz !!%%""%%)),,55115511::::??BBDDBBEEJJHHLLMMPPTTQQWWYYZZ\\^^``ccggiijjoollqqvvttyy{{~~‰ËŎƐǒȕʙ˙̟ϡϢѥҩөԭ֯ױױصڻݼ,' H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIpִQ:(RJI;HGSSFAPȑA!rC+j D#:S Y:A mSNF1Rg.=2 @ ;5A)s.:)v 0`ϟlnp#rdDD#xЙ 643#LTFyPE+]s2Qk( ;gGΗPfh ( oNr,NiHG0^s& *92;!lX_mwDGU7 DX qIRw5EA&9MdMDHM(އhcYC$#!~8@I$~! $pP |@ c11abRI!``a㠁Y2qkD;Pv}6jǍ0}F^ipZDE ph2+ar&C }t.GEbC |,s69 P( y0DpVft%Af.KH?,nb9"|/GAH"} A#w:p;x5$sE-I";[Xwu85!KV}[A]$ܩepG pYC@ڄkn:m VXf2 BYzD3 ,.zs9PBD\ lf4y",Bscdqf(6J袋@\[$z@@B ˦=5ɢE8H Dk8F{R= ~}Ν `g-1,RBHe-Ms (!{QHm ` AcRf!F &D `Dvd!B07 ,^lأRPIh~ @r)`$ hC@AG"yX mB4i Y(D8& F+1Rh KIH+ @EJ I* #RWDBhD ,6o| m#DxBЪV@$Y B yC$B*$} ZE @asPJoQ| Η?BYeJB8JH,iuJ&9a!r(#D|,9|D'yF)_st$ @2^o'ЯCh>@dz,F!QHB6I( E9E;C\oh2B5+$T}mHCه:VGjM0$8!mhApfBɏ@ m:O<6t}p<1@"t$H "BZ-6lgq,:@|P aF #Q!a'Qi];$}^V_xpmѳq8K`m[@(m`q! B /[mrg&^&qt$ 6g)l ];FpHA(]r Ƃb`QAFkq72-KMΧh xw=XvA@@m‡ƺXZO/ ?xă(+D,d9}Ev XԽIe 0]4y}'W!)] B|Fq D ͧ?s!#F3_ӣ738 N>@8lH q[ JƱ7(hE6,sI7)F0Vp`[%W25fc"8t.Aa!D@i_qeG#UT4PFxE vDa~ R t<"(WAl-[uf$P%~w9W@xwHv{9whV65P\ "ufoDd2g>6-c0(Y< 1"1O*p)ЊPj*25 0% (@BanS{ DN/%Jҍ  (3 b1$X]RP9Z*)~N-#r]NhGpl с^@FY4}b/M !0U|Me=dE$>pM ~rJ-&&@.\ 87{3`%0ds+1Hh22PK3 W0uE)*U))+ @50FtEOKHP@}^ jH0}U`10 k咹EcVUK$A_z`TEΑUɕ4A֓<RrfPGBza"gd62(ayImF"qc("gAyP0i@eESҘYO9b4"}"x@'Pupj`22,*&qٕf%E+]B%f0YJ3f?1,/p?;}XV5Q%H1Z4JmpOP7d=O y;!ӑpeq!F PP-eKfw.lzp`- j`o@EPOv*RzUP uS@Ĩ!IO*PEAO` p\ P 1{:LSPU@QzRʪ#4PG`Nڬ;OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/ReaderWriterLua.cpp0000644000175000017500000001672113151044751026340 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include "LuaScriptEngine.h" class ReaderWriterLua : public osgDB::ReaderWriter { public: ReaderWriterLua() { supportsExtension("lua","lua script"); } virtual const char* className() const { return "Lua ScriptEngine plugin"; } lua::LuaScriptEngine* createScriptEngine(const osgDB::ReaderWriter::Options* options) const { osg::ref_ptr se = new lua::LuaScriptEngine(); // add file paths if (options) se->addPaths(options); else se->addPaths(osgDB::Registry::instance()->getOptions()); return se.release(); } virtual ReadResult readObjectFromScript(std::istream& fin, const osgDB::ReaderWriter::Options* options =NULL) const { ReadResult result = readScript(fin, options); if (!result.validObject()) return result; osg::ref_ptr script = dynamic_cast(result.getObject()); if (!script) return ReadResult::ERROR_IN_READING_FILE; std::string entryPoint = ""; osg::Parameters inputParameters; osg::Parameters outputParameters; osg::ref_ptr se = createScriptEngine(options); if (!se->run(script.get(), entryPoint, inputParameters, outputParameters)) return 0; if (outputParameters.empty()) return 0; typedef std::vector< osg::ref_ptr > Objects; Objects objects; for(osg::Parameters::iterator itr = outputParameters.begin(); itr != outputParameters.end(); ++itr) { osg::Object* object = dynamic_cast(itr->get()); if (object) objects.push_back(object); } if (objects.empty()) return 0; if (objects.size()==1) { return objects[0].get(); } osg::ref_ptr group = new osg::Group; for(Objects::iterator itr = objects.begin(); itr != objects.end(); ++itr) { osg::Node* node = dynamic_cast(itr->get()); if (node) group->addChild(node); } if (group->getNumChildren()>0) return group.get(); else return 0; } virtual ReadResult readObject(std::istream& fin, const osgDB::ReaderWriter::Options* options =NULL) const { return readObjectFromScript(fin, options); } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { if (file=="ScriptEngine.lua") { return createScriptEngine(options); } std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); osgDB::ifstream istream(fileName.c_str(), std::ios::in); if(!istream) return ReadResult::FILE_NOT_HANDLED; return readObject(istream, local_opt.get()); } virtual ReadResult readImage(std::istream& fin, const osgDB::ReaderWriter::Options* options =NULL) const { return readObjectFromScript(fin, options); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); osgDB::ifstream istream(fileName.c_str(), std::ios::in); if(!istream) return ReadResult::FILE_NOT_HANDLED; return readImage(istream, local_opt.get()); } virtual ReadResult readNode(std::istream& fin, const osgDB::ReaderWriter::Options* options =NULL) const { return readObjectFromScript(fin, options); } virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); osgDB::ifstream istream(fileName.c_str(), std::ios::in); if(!istream) return ReadResult::FILE_NOT_HANDLED; return readNode(istream, local_opt.get()); } virtual ReadResult readScript(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const { osg::ref_ptr script = new osg::Script; script->setLanguage("lua"); std::string str; while(fin) { int c = fin.get(); if (c>=0 && c<=255) { str.push_back(c); } } script->setScript(str); return script.release(); } virtual ReadResult readScript(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osgDB::ifstream istream(fileName.c_str(), std::ios::in); if(!istream) return ReadResult::FILE_NOT_HANDLED; return readScript(istream, options); } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(lua, ReaderWriterLua) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/CMakeLists.txt0000644000175000017500000000310413151044751025322 0ustar albertoalbertoSET(TARGET_H LuaScriptEngine.h ) SET(TARGET_SRC LuaScriptEngine.cpp ReaderWriterLua.cpp ) IF (OSG_USE_LOCAL_LUA_SOURCE) IF( CMAKE_SYSTEM MATCHES "Linux" ) ADD_DEFINITIONS(-DLUA_USE_LINUX) ELSEIF(APPLE) ADD_DEFINITIONS(-DLUA_USE_MACOSX) ENDIF() SET(LUA_SRC_DIR lua-5.2.3/src) SET(LUA_INCLUDE_DIR ${LUA_SRC_DIR}) SET(LUA_CORE_SRC ${LUA_SRC_DIR}/lapi.c ${LUA_SRC_DIR}/lcode.c ${LUA_SRC_DIR}/lctype.c ${LUA_SRC_DIR}/ldebug.c ${LUA_SRC_DIR}/ldo.c ${LUA_SRC_DIR}/ldump.c ${LUA_SRC_DIR}/lfunc.c ${LUA_SRC_DIR}/lgc.c ${LUA_SRC_DIR}/llex.c ${LUA_SRC_DIR}/lmem.c ${LUA_SRC_DIR}/lobject.c ${LUA_SRC_DIR}/lopcodes.c ${LUA_SRC_DIR}/lparser.c ${LUA_SRC_DIR}/lstate.c ${LUA_SRC_DIR}/lstring.c ${LUA_SRC_DIR}/ltable.c ${LUA_SRC_DIR}/ltm.c ${LUA_SRC_DIR}/lundump.c ${LUA_SRC_DIR}/lvm.c ${LUA_SRC_DIR}/lzio.c ) SET(LUA_LIB_SRC ${LUA_SRC_DIR}/lauxlib.c ${LUA_SRC_DIR}/lbaselib.c ${LUA_SRC_DIR}/lbitlib.c ${LUA_SRC_DIR}/lcorolib.c ${LUA_SRC_DIR}/ldblib.c ${LUA_SRC_DIR}/liolib.c ${LUA_SRC_DIR}/lmathlib.c ${LUA_SRC_DIR}/loslib.c ${LUA_SRC_DIR}/lstrlib.c ${LUA_SRC_DIR}/ltablib.c ${LUA_SRC_DIR}/loadlib.c ${LUA_SRC_DIR}/linit.c ) SET(TARGET_SRC ${TARGET_SRC} ${LUA_CORE_SRC} ${LUA_LIB_SRC}) SET(TARGET_H ${TARGET_H} ${LUA_H}) INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR} ) ELSE() SET(TARGET_EXTERNAL_LIBRARIES ${TARGET_EXTERNAL_LIBRARIES} ${LUA_LIBRARY}) INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR} ) ENDIF() #### end var setup ### SETUP_PLUGIN(lua) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/LuaScriptEngine.h0000644000175000017500000002275413151044751026003 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #ifndef LUASCRIPTENGINE_H #define LUASCRIPTENGINE_H #include #include extern "C" { #include #include #include } namespace lua { // forward declare class LuaScriptEngine; struct SerializerScratchPad : public osg::Referenced { SerializerScratchPad(unsigned int s=256) : deleteData(true), dataType(osgDB::BaseSerializer::RW_UNDEFINED), dataSize(0) { maxDataSize = s; data = new char[s]; } SerializerScratchPad(osgDB::BaseSerializer::Type type, const void* ptr, unsigned int s) : deleteData(false), maxDataSize(s), data(const_cast(reinterpret_cast(ptr))), dataType(type),dataSize(s) {} virtual ~SerializerScratchPad() { if (deleteData && data) delete [] data; } bool deleteData; unsigned int maxDataSize; char* data; osgDB::BaseSerializer::Type dataType; unsigned int dataSize; void reset() { dataType = osgDB::BaseSerializer::RW_UNDEFINED; dataSize = 0; } template bool set(const T& t) { if (sizeof(T)<=maxDataSize) { *(reinterpret_cast(data)) = t; dataType = osgDB::getTypeEnum(); dataSize = sizeof(T); return true; } else { dataSize = 0; dataType = osgDB::BaseSerializer::RW_UNDEFINED; return false; } } template bool get(T& t) const { if (sizeof(T)==dataSize && dataType == osgDB::getTypeEnum()) { t = *(reinterpret_cast(data)); return true; } else { return false; } } }; class LuaScriptEngine : public osg::ScriptEngine { public: LuaScriptEngine(); LuaScriptEngine(const LuaScriptEngine& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); META_Object(lua, LuaScriptEngine) virtual const std::string& getLanguage() const { return _language; } /** run a Script.*/ virtual bool run(osg::Script* script, const std::string& entryPoint, osg::Parameters& inputParameters, osg::Parameters& outputParameters); /** get the lua_State object.*/ lua_State* getLuaState() const { return _lua; } osgDB::ClassInterface& getClassInterface() const { return _ci; } int pushDataToStack(SerializerScratchPad* ssp) const; int getDataFromStack(SerializerScratchPad* ssp, osgDB::BaseSerializer::Type type, int pos) const; int pushPropertyToStack(osg::Object* object, const std::string& propertyName) const; int setPropertyFromStack(osg::Object* object, const std::string& propertyName) const; int setPropertyFromStack(osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type type) const; bool loadScript(osg::Script* script); int getAbsolutePos(int pos) const { return (pos<0) ? (lua_gettop(_lua)+pos+1) : pos; } osgDB::BaseSerializer::Type getType(int pos) const; bool getfields(int pos, const char* f1, const char* f2, int type) const; bool getfields(int pos, const char* f1, const char* f2, const char* f3, int type) const; bool getfields(int pos, const char* f1, const char* f2, const char* f3, const char* f4, int type) const; bool getfields(int pos, const char* f1, const char* f2, const char* f3, const char* f4, const char* f5, const char* f6, int type) const; bool getelements(int pos, int numElements, int type) const; bool getvec2(int pos) const; bool getvec3(int pos) const; bool getvec4(int pos) const; bool getmatrix(int pos) const; bool getboundingbox(int pos) const; bool getboundingsphere(int pos) const; bool getValue(int pos, osg::Vec2f& value) const; bool getValue(int pos, osg::Vec3f& value) const; bool getValue(int pos, osg::Vec4f& value) const; bool getValue(int pos, osg::Vec2d& value) const; bool getValue(int pos, osg::Vec3d& value) const; bool getValue(int pos, osg::Vec4d& value) const; bool getValue(int pos, osg::Quat& value) const; bool getValue(int pos, osg::Plane& value) const; bool getValue(int pos, osg::Matrixf& value) const; bool getValue(int pos, osg::Matrixd& value) const; bool getValue(int pos, osg::BoundingBoxf& value) const; bool getValue(int pos, osg::BoundingBoxd& value) const; bool getValue(int pos, osg::BoundingSpheref& value) const; bool getValue(int pos, osg::BoundingSphered& value) const; void pushValue(osgDB::BaseSerializer::Type type, const void* ptr) const; void pushValue(const osg::Vec2f& value) const; void pushValue(const osg::Vec3f& value) const; void pushValue(const osg::Vec4f& value) const; void pushValue(const osg::Vec2d& value) const; void pushValue(const osg::Vec3d& value) const; void pushValue(const osg::Vec4d& value) const; void pushValue(const osg::Quat& value) const; void pushValue(const osg::Plane& value) const; void pushValue(const osg::Matrixf& value) const; void pushValue(const osg::Matrixd& value) const; void pushValue(const osg::BoundingBoxf& value) const; void pushValue(const osg::BoundingBoxd& value) const; void pushValue(const osg::BoundingSpheref& value) const; void pushValue(const osg::BoundingSphered& value) const; bool pushParameter(osg::Object* object) const; bool popParameter(osg::Object* object) const; osg::Object* popParameterObject() const; void pushContainer(osg::Object* object, const std::string& propertyName) const; void createAndPushObject(const std::string& compoundName) const; void pushObject(osg::Object* object) const; void pushAndCastObject(const std::string& compoundClassName, osg::Object* object) const; template T* getObjectFromTable(int pos) const { if (lua_type(_lua, pos)==LUA_TTABLE) { lua_pushstring(_lua, "object_ptr"); lua_rawget(_lua, pos); osg::Object* object = (lua_type(_lua, -1)==LUA_TUSERDATA)? *const_cast(reinterpret_cast(lua_touserdata(_lua,-1))) : 0; lua_pop(_lua,1); return dynamic_cast(object); } else return 0; } std::string getStringFromTable(int pos, const std::string& field) const { std::string result; if (lua_type(_lua, pos)==LUA_TTABLE) { lua_pushstring(_lua, field.c_str()); lua_rawget(_lua, pos); if (lua_type(_lua, -1)==LUA_TSTRING) { result = lua_tostring(_lua, -1); } lua_pop(_lua,1); } return result; } std::string getObjectCompoundClassName(int pos) const { if (lua_type(_lua, pos)==LUA_TTABLE) { lua_pushstring(_lua, "compoundClassName"); lua_rawget(_lua, pos); std::string compoundClassName = lua_tostring(_lua, -1); lua_pop(_lua,1); return compoundClassName; } else return std::string(""); } void assignClosure(const char* name, lua_CFunction fn) const; bool matchLuaParameters(int luaType1) const { return ((lua_gettop(_lua)==1) && (lua_type(_lua, 1)==luaType1)); } bool matchLuaParameters(int luaType1, int luaType2) const { return ((lua_gettop(_lua)==2) && (lua_type(_lua, 1)==luaType1) && (lua_type(_lua, 2)==luaType2)); } bool matchLuaParameters(int luaType1, int luaType2, int luaType3) const { return ((lua_gettop(_lua)==3) && (lua_type(_lua, 1)==luaType1) && (lua_type(_lua, 2)==luaType2) && (lua_type(_lua, 3)==luaType3)); } bool matchLuaParameters(int luaType1, int luaType2, int luaType3, int luaType4) const { return ((lua_gettop(_lua)==4) && (lua_type(_lua, 1)==luaType1) && (lua_type(_lua, 2)==luaType2) && (lua_type(_lua, 3)==luaType3) && (lua_type(_lua, 4)==luaType4)); } std::string lookUpGLenumString(GLenum value) const; GLenum lookUpGLenumValue(const std::string& str) const; void addPaths(const osgDB::FilePathList& paths); void addPaths(const osgDB::Options* options); protected: void initialize(); virtual ~LuaScriptEngine(); lua_State* _lua; unsigned int _scriptCount; std::string createUniquieScriptName(); typedef std::map< osg::ref_ptr, std::string> ScriptMap; ScriptMap _loadedScripts; mutable osgDB::ClassInterface _ci; }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/lua/LuaScriptEngine.cpp0000644000175000017500000044641313151044751026340 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include "LuaScriptEngine.h" #include #include #include using namespace lua; class LuaCallbackObject : public osg::CallbackObject { public: LuaCallbackObject(const std::string& methodName, const LuaScriptEngine* lse, int ref):_lse(lse),_ref(ref) { setName(methodName); } virtual bool run(osg::Object* object, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const { int topBeforeCall = lua_gettop(_lse->getLuaState()); lua_rawgeti(_lse->getLuaState(), LUA_REGISTRYINDEX, _ref); int numInputs = 1; _lse->pushParameter(object); for(osg::Parameters::iterator itr = inputParameters.begin(); itr != inputParameters.end(); ++itr) { _lse->pushParameter(itr->get()); ++numInputs; } if (lua_pcall(_lse->getLuaState(), numInputs, LUA_MULTRET,0)!=0) { OSG_NOTICE<<"Lua error : "<getLuaState(), -1)<getLuaState()); int numReturns = topAfterCall-topBeforeCall; for(int i=1; i<=numReturns; ++i) { outputParameters.insert(outputParameters.begin(), _lse->popParameterObject()); } return true; } int getRef() const { return _ref; } protected: osg::ref_ptr _lse; int _ref; }; static int getProperty(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==2 && lua_type(_lua, 1)==LUA_TTABLE) { if (lua_type(_lua, 2)==LUA_TSTRING) { std::string propertyName = lua_tostring(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); return lse->pushPropertyToStack(object, propertyName); } } OSG_NOTICE<<"Warning: Lua getProperty() not matched"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==3 && lua_type(_lua, 1)==LUA_TTABLE) { if (lua_type(_lua, 2)==LUA_TSTRING) { std::string propertyName = lua_tostring(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); return lse->setPropertyFromStack(object, propertyName); } } OSG_NOTICE<<"Warning: Lua setProperty() not matched"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==2 && lua_type(_lua, 1)==LUA_TTABLE) { if (lua_type(_lua, 2)==LUA_TSTRING) { std::string propertyName = lua_tostring(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); return lse->pushPropertyToStack(object, propertyName); } else if (lua_type(_lua, 2)==LUA_TNUMBER) { double index = lua_tonumber(_lua, 2); const osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { const void* dataPtr = vs->getElement(*object, (unsigned int) index); if (dataPtr) { SerializerScratchPad valuesp(vs->getElementType(), dataPtr, vs->getElementSize()); return lse->pushDataToStack(&valuesp); } else { lua_pushnil(_lua); return 1; } } } } OSG_NOTICE<<"Warning: Lua getContainerProperty() not matched"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==3 && lua_type(_lua, 1)==LUA_TTABLE) { if (lua_type(_lua, 2)==LUA_TSTRING) { std::string propertyName = lua_tostring(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); return lse->setPropertyFromStack(object, propertyName); } else if (lua_type(_lua, 2)==LUA_TNUMBER) { double index = lua_tonumber(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { SerializerScratchPad ssp; lse->getDataFromStack(&ssp, vs->getElementType(), 3); { vs->setElement(*object, (unsigned int) index, ssp.data); } } return 0; } } OSG_NOTICE<<"Warning: Lua setContainerProperty() not matched"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { lua_pushinteger(lse->getLuaState(), vs->size(*object)); return 1; } return 0; } static int callVectorClear(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { vs->clear(*object); return 0; } return 0; } static int callVectorResize(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE || lua_type(_lua, 2)!=LUA_TNUMBER) return 0; double numElements = lua_tonumber(lse->getLuaState(),2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { vs->resize(*object, static_cast(numElements)); } return 0; } static int callVectorReserve(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE || lua_type(_lua, 2)!=LUA_TNUMBER) return 0; double numElements = lua_tonumber(lse->getLuaState(),2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { vs->reserve(*object, static_cast(numElements)); } return 0; } static int callVectorAdd(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); if (vs) { SerializerScratchPad ssp; lse->getDataFromStack(&ssp, vs->getElementType(), 2); if (ssp.dataType==vs->getElementType()) { vs->addElement(*object, ssp.data); } else { OSG_NOTICE<<"Failed to match table type"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==2 && lua_type(_lua, 1)==LUA_TTABLE) { if (lua_type(_lua, 2)==LUA_TSTRING) { std::string propertyName = lua_tostring(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); return lse->pushPropertyToStack(object, propertyName); } else { const osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (ms) { SerializerScratchPad keysp; lse->getDataFromStack(&keysp, ms->getKeyType(),2); if (keysp.dataType==ms->getKeyType()) { const void* dataPtr = ms->getElement(*object, keysp.data); if (dataPtr) { SerializerScratchPad valuesp(ms->getElementType(), dataPtr, ms->getElementSize()); return lse->pushDataToStack(&valuesp); } else { lua_pushnil(_lua); return 1; } return 0; } } } } OSG_NOTICE<<"Warning: Lua getMapProperty() not matched"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==3 && lua_type(_lua, 1)==LUA_TTABLE) { if (lua_type(_lua, 2)==LUA_TSTRING) { std::string propertyName = lua_tostring(_lua, 2); osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); return lse->setPropertyFromStack(object, propertyName); } else { osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (ms) { SerializerScratchPad keysp, valuesp; lse->getDataFromStack(&keysp, ms->getKeyType(),2); lse->getDataFromStack(&valuesp, ms->getElementType(),3); if (keysp.dataType==ms->getKeyType() && ms->getElementType()==valuesp.dataType) { ms->setElement(*object, keysp.data, valuesp.data); return 0; } else { OSG_NOTICE<<"Warning: Lua setMapProperty() : Failed to matched map element "<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (ms) { ms->clear(*object); return 0; } return 0; } static int getMapSize(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (ms) { lua_pushinteger(lse->getLuaState(), ms->size(*object)); return 1; } return 0; } static int createMapIterator(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (ms) { lse->pushObject(ms->createIterator(*object)); return 1; } return 0; } static int createMapReverseIterator(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Object* object = lse->getObjectFromTable(1); std::string containerPropertyName = lse->getStringFromTable(1,"containerPropertyName"); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = lse->getClassInterface().getSerializer(object, containerPropertyName, type); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (ms) { lse->pushObject(ms->createReverseIterator(*object)); return 1; } return 0; } ////////////////////////////////////////////////////////////////////////////////////// // // MapIteratorObject support // static int callMapIteratorAdvance(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); if (lua_gettop(_lua)<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osgDB::MapIteratorObject* mio = lse->getObjectFromTable(1); if (mio) { lua_pushboolean(lse->getLuaState(), mio->advance()); return 1; } return 0; } static int callMapIteratorValid(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); if (lua_gettop(_lua)<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osgDB::MapIteratorObject* mio = lse->getObjectFromTable(1); if (mio) { lua_pushboolean(lse->getLuaState(), mio->valid()); return 1; } return 0; } static int getMapIteratorKey(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); if (lua_gettop(_lua)<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osgDB::MapIteratorObject* mio = lse->getObjectFromTable(1); if (mio) { const void* dataPtr = mio->getKey(); if (dataPtr) { SerializerScratchPad valuesp(mio->getKeyType(), dataPtr, mio->getKeySize()); return lse->pushDataToStack(&valuesp); } else { lua_pushnil(_lua); return 1; } } return 0; } static int getMapIteratorElement(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); if (lua_gettop(_lua)<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osgDB::MapIteratorObject* mio = lse->getObjectFromTable(1); if (mio) { const void* dataPtr = mio->getElement(); if (dataPtr) { SerializerScratchPad valuesp(mio->getElementType(), dataPtr, mio->getElementSize()); return lse->pushDataToStack(&valuesp); } else { lua_pushnil(_lua); return 1; } } OSG_NOTICE<<"getMapIteratorElement failed. "<(lua_topointer(_lua, lua_upvalueindex(1))); if (lua_gettop(_lua)<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osgDB::MapIteratorObject* mio = lse->getObjectFromTable(1); if (mio) { SerializerScratchPad valuesp; lse->getDataFromStack(&valuesp, mio->getElementType(), 2); if (mio->getElementType()==valuesp.dataType) { mio->setElement(valuesp.data); return 0; } else { OSG_NOTICE<<"Warning: Lua setMapIteratorElement() : Failed to matched map element type, valuesp.dataType="<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::StateSet* stateset = lse->getObjectFromTable(1); if (!stateset) { OSG_NOTICE<<"Warning: StateSet:add() can only be called on a StateSet"<getObjectFromTable(2); osg::StateAttribute* sa = dynamic_cast(po); osg::Uniform* uniform = dynamic_cast(po); osg::StateAttribute::OverrideValue value=osg::StateAttribute::ON; bool setOnOff = false; if (n>=3 && lua_type(_lua,3)==LUA_TSTRING) { value = convertStringToStateAttributeValue(lua_tostring(_lua, 3), value, setOnOff); } if (sa) { if (setOnOff) { if (sa->isTextureAttribute()) stateset->setTextureAttributeAndModes(0, sa, value); else stateset->setAttributeAndModes(sa, value); } else { if (sa->isTextureAttribute()) stateset->setTextureAttribute(0, sa, value); else stateset->setAttribute(sa, value); } return 0; } else if (uniform) { stateset->addUniform(uniform, value); return 0; } } else if (lua_type(_lua,2)==LUA_TNUMBER) { double index = lua_tonumber(_lua, 2); if (n>=3) { if (lua_type(_lua,3)==LUA_TTABLE) { osg::Object* po = lse->getObjectFromTable(3); osg::StateAttribute* sa = dynamic_cast(po); osg::StateAttribute::OverrideValue value=osg::StateAttribute::ON; bool setOnOff = false; if (n>=4 && lua_type(_lua,4)==LUA_TSTRING) { value = convertStringToStateAttributeValue(lua_tostring(_lua, 4), value, setOnOff); } if (sa) { if (setOnOff) { stateset->setTextureAttributeAndModes(static_cast(index), sa, value); } else { stateset->setTextureAttribute(static_cast(index), sa, value); } return 0; } } else if (lua_type(_lua,3)==LUA_TSTRING) { std::string modeString = lua_tostring(_lua, 3); GLenum mode = lse->lookUpGLenumValue(modeString); osg::StateAttribute::OverrideValue value=osg::StateAttribute::ON; bool setOnOff = false; if (n>=4 && lua_type(_lua,4)==LUA_TSTRING) { value = convertStringToStateAttributeValue(lua_tostring(_lua, 4), value, setOnOff); } stateset->setTextureMode(static_cast(index), mode, value); return 0; } } } else if (lua_type(_lua,2)==LUA_TSTRING) { std::string modeString = lua_tostring(_lua, 2); GLenum mode = lse->lookUpGLenumValue(modeString); if (n>=3) { osg::StateAttribute::OverrideValue value=osg::StateAttribute::ON; bool setOnOff = false; if (lua_type(_lua,3)==LUA_TSTRING) { value = convertStringToStateAttributeValue(lua_tostring(_lua, 3), value, setOnOff); } stateset->setMode(mode, value); return 0; } } OSG_NOTICE<<"Warning: StateSet:set() inappropriate parameters, use form:"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::StateSet* stateset = lse->getObjectFromTable(1); if (!stateset) { OSG_NOTICE<<"Warning: StateSet:get() can only be called on a StateSet"<(lua_tonumber(_lua, 2)); if (lua_type(_lua,3)==LUA_TTABLE) { osg::Object* po = lse->getObjectFromTable(3); osg::StateAttribute* sa = dynamic_cast(po); if (sa && sa->isTextureAttribute()) { if (stateset->getTextureAttributeList().size()>index) { const osg::StateSet::AttributeList& al = stateset->getTextureAttributeList()[index]; for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (itr->second.first==sa) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } } OSG_NOTICE<<"Warning: StateSet:get() Could not find attribute : "<className()<getTextureAttributeList().size()>index) { const osg::StateSet::AttributeList& al = stateset->getTextureAttributeList()[index]; for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (value == itr->second.first->className() || value == itr->second.first->getName()) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } } if (stateset->getTextureModeList().size()>index) { osg::StateAttribute::GLMode mode = lse->lookUpGLenumValue(value); const osg::StateSet::ModeList& ml = stateset->getTextureModeList()[index]; for(osg::StateSet::ModeList::const_iterator itr = ml.begin(); itr != ml.end(); ++itr) { if (mode == itr->first) { lua_pushstring(_lua, convertStateAttributeValueToString(itr->second, true).c_str()); return 1; } } } OSG_NOTICE<<"Warning: StateSet:get() Could not find attribute : "<getObjectFromTable(2); osg::StateAttribute* sa = dynamic_cast(po); osg::Uniform* uniform = dynamic_cast(po); if (sa && sa->isTextureAttribute() && stateset->getTextureAttributeList().size()>0) { const osg::StateSet::AttributeList& al = stateset->getTextureAttributeList()[0]; for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (itr->second.first==sa) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } OSG_NOTICE<<"Warning: StateSet:get("<className()<<") Could not find attribute"<getAttributeList(); for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (itr->second.first==sa) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } OSG_NOTICE<<"Warning: StateSet:get("<className()<<") Could not find attribute"<getUniformList(); for(osg::StateSet::UniformList::const_iterator itr = ul.begin(); itr != ul.end(); ++itr) { if (itr->second.first==uniform) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } OSG_NOTICE<<"Warning: StateSet:get("<className()<<") Could not find uniform"<getAttributeList(); for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (value == itr->second.first->className() || value == itr->second.first->getName()) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } const osg::StateSet::UniformList& ul = stateset->getUniformList(); for(osg::StateSet::UniformList::const_iterator itr = ul.begin(); itr != ul.end(); ++itr) { if (value == itr->second.first->className() || value == itr->second.first->getName()) { lua_newtable(_lua); lua_pushstring(_lua, "attribute"); lse->pushObject(itr->second.first.get()); lua_settable(_lua, -3); lua_pushstring(_lua, "value"); lua_pushstring(_lua, convertStateAttributeValueToString(itr->second.second, false).c_str()); lua_settable(_lua, -3); return 1; } } osg::StateAttribute::GLMode mode = lse->lookUpGLenumValue(value); const osg::StateSet::ModeList& ml = stateset->getModeList(); for(osg::StateSet::ModeList::const_iterator itr = ml.begin(); itr != ml.end(); ++itr) { if (mode == itr->first) { lua_pushstring(_lua, convertStateAttributeValueToString(itr->second, true).c_str()); return 1; } } OSG_NOTICE<<"Warning: StateSet:get("<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::StateSet* stateset = lse->getObjectFromTable(1); if (!stateset) { OSG_NOTICE<<"Warning: StateSet:remove() can only be called on a StateSet"<(lua_tonumber(_lua, 2)); if (lua_type(_lua,3)==LUA_TTABLE) { osg::Object* po = lse->getObjectFromTable(3); osg::StateAttribute* sa = dynamic_cast(po); stateset->removeTextureAttribute(static_cast(index), sa); return 0; } else if (lua_type(_lua,3)==LUA_TSTRING) { std::string value = lua_tostring(_lua, 3); if (stateset->getTextureAttributeList().size()>index) { const osg::StateSet::AttributeList& al = stateset->getTextureAttributeList()[index]; for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (value == itr->second.first->className() || value == itr->second.first->getName()) { stateset->removeTextureAttribute(index, itr->second.first.get()); return 0; } } } if (stateset->getTextureModeList().size()>index) { osg::StateAttribute::GLMode mode = lse->lookUpGLenumValue(value); const osg::StateSet::ModeList& ml = stateset->getTextureModeList()[static_cast(index)]; for(osg::StateSet::ModeList::const_iterator itr = ml.begin(); itr != ml.end(); ++itr) { if (mode == itr->first) { stateset->removeTextureMode(static_cast(index), mode); return 1; } } } OSG_NOTICE<<"Warning: StateSet:remove("<getObjectFromTable(2); osg::StateAttribute* sa = dynamic_cast(po); osg::Uniform* uniform = dynamic_cast(po); if (sa && sa->isTextureAttribute()) { stateset->removeTextureAttribute(0, sa); return 0; } else if (sa) { stateset->removeAttribute(sa); return 0; } else if (uniform) { stateset->removeUniform(uniform); return 0; } } else if (lua_type(_lua,2)==LUA_TSTRING) { std::string value = lua_tostring(_lua, 2); const osg::StateSet::AttributeList& al = stateset->getAttributeList(); for(osg::StateSet::AttributeList::const_iterator itr = al.begin(); itr != al.end(); ++itr) { if (value == itr->second.first->className() || value == itr->second.first->getName()) { stateset->removeAttribute(itr->second.first.get()); return 0; } } const osg::StateSet::UniformList& ul = stateset->getUniformList(); for(osg::StateSet::UniformList::const_iterator itr = ul.begin(); itr != ul.end(); ++itr) { if (value == itr->second.first->className() || value == itr->second.first->getName()) { stateset->removeUniform(itr->second.first.get()); return 0; } } osg::StateAttribute::GLMode mode = lse->lookUpGLenumValue(value); const osg::StateSet::ModeList& ml = stateset->getModeList(); for(osg::StateSet::ModeList::const_iterator itr = ml.begin(); itr != ml.end(); ++itr) { if (mode == itr->first) { stateset->removeMode(mode); return 1; } } OSG_NOTICE<<"Warning: StateSet:remove("<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Image* image = lse->getObjectFromTable(1); if (!image) { OSG_NOTICE<<"Warning: Image:allocate() can only be called on a Image"<=2 && lua_isnumber(_lua, 2)) s = static_cast(lua_tonumber(_lua, 2)); if (n>=3 && lua_isnumber(_lua, 3)) t = static_cast(lua_tonumber(_lua, 3)); if (n>=4 && lua_isnumber(_lua, 4)) r = static_cast(lua_tonumber(_lua, 4)); if (n>=5) { if (lua_isnumber(_lua, 5)) pixelFormat = static_cast(lua_tonumber(_lua, 5)); else if (lua_isstring(_lua, 5)) { pixelFormat = lse->lookUpGLenumValue(lua_tostring(_lua,5)); } } if (n>=6) { if (lua_isnumber(_lua, 6)) dataType = static_cast(lua_tonumber(_lua, 6)); else if (lua_isstring(_lua, 6)) { dataType = lse->lookUpGLenumValue(lua_tostring(_lua,6)); } } if (n>=7) { if (lua_isnumber(_lua, 7)) packing = static_cast(lua_tonumber(_lua, 7)); } if (s<=0 || t<=0 || r<=0 || pixelFormat==0 || dataType==0) { OSG_NOTICE<<"Warning: Cannot not image:allocator("<allocateImage(s,t,r,pixelFormat,dataType,packing); return 0; } static int callImageS(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Image* image = lse->getObjectFromTable(1); if (!image) { OSG_NOTICE<<"Warning: Image:s() can only be called on a Image"<s()); return 1; } static int callImageT(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Image* image = lse->getObjectFromTable(1); if (!image) { OSG_NOTICE<<"Warning: Image:t() can only be called on a Image"<t()); return 1; } static int callImageR(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Image* image = lse->getObjectFromTable(1); if (!image) { OSG_NOTICE<<"Warning: Image:r() can only be called on a Image"<r()); return 1; } // conversion of a lua value/table to a std::string, supports recursion when tables contain tables static std::string cpp_tostring(lua_State* _lua, int index) { if (!lua_istable(_lua, index)) { const char* str = lua_tostring(_lua, index); if (str) { return str; } else { return "value-cannot-be-converted-to-string"; } } // Push another reference to the table on top of the stack (so we know // where it is, and this function can work for negative, positive and // pseudo indices lua_pushvalue(_lua, index); // stack now contains: -1 => table lua_pushnil(_lua); // stack now contains: -1 => nil; -2 => table bool first = true; std::string str("{"); while (lua_next(_lua, -2)) { if (!first) str.append(", "); else first = false; // stack now contains: -1 => value; -2 => key; -3 => table // copy the key so that lua_tostring does not modify the original lua_pushvalue(_lua, -2); // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table // handle key if (lua_isstring(_lua, -1)) { const char *key = lua_tostring(_lua, -1); if (key) { str.append(key); str.append("="); } } // handle value if (lua_istable(_lua, -2)) { str.append(cpp_tostring(_lua,-2)); } else if (lua_isfunction(_lua, -2)) { str.append("function"); } else if (lua_isnil(_lua, -2)) { str.append("nil"); } else if (lua_isstring(_lua,-2)) { const char *value = lua_tostring(_lua, -2); str.append("\""); if (value) { str.append(value); } str.append("\""); } else { const char *value = lua_tostring(_lua, -2); if (value) { str.append(value); } } // pop value + copy of key, leaving original key lua_pop(_lua, 2); // stack now contains: -1 => key; -2 => table } str.append("}"); // stack now contains: -1 => table (when lua_next returns 0 it pops the key // but does not push anything.) // Pop table lua_pop(_lua, 1); // Stack is now the same as it was on entry to this function return str; } static int tostring(lua_State* _lua) { lua_pushstring(_lua, cpp_tostring(_lua,-1) .c_str()); return 1; } static int callImageGet(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Image* image = lse->getObjectFromTable(1); if (!image) { OSG_NOTICE<<"Warning: Image:get() can only be called on a Image"<=2 && lua_isnumber(_lua, 2)) i = static_cast(lua_tonumber(_lua, 2)); if (n>=3 && lua_isnumber(_lua, 3)) j = static_cast(lua_tonumber(_lua, 3)); if (n>=4 && lua_isnumber(_lua, 4)) k = static_cast(lua_tonumber(_lua, 4)); const unsigned char* ptr = image->data(i,j,k); unsigned int numComponents = osg::Image::computeNumComponents(image->getPixelFormat()); // OSG_NOTICE<<"Need to implement Image::get("<getPixelFormat()) { case(GL_INTENSITY): lua_pushnumber(_lua, colour[0]); return 1; case(GL_LUMINANCE): lua_pushnumber(_lua, colour[0]); return 1; case(GL_ALPHA): lua_pushnumber(_lua, colour[0]); return 1; case(GL_LUMINANCE_ALPHA): { lua_newtable(_lua); luaL_getmetatable(_lua, "LuaScriptEngine.Table"); lua_setmetatable(_lua, -2); lua_pushstring(_lua, "luminance"); lua_pushnumber(_lua, colour[0]); lua_settable(_lua, -3); lua_pushstring(_lua, "alpha"); lua_pushnumber(_lua, colour[1]); lua_settable(_lua, -3); return 1; } case(GL_RGB): { lua_newtable(_lua); luaL_getmetatable(_lua, "LuaScriptEngine.Table"); lua_setmetatable(_lua, -2); lua_pushstring(_lua, "red"); lua_pushnumber(_lua, colour[0]); lua_settable(_lua, -3); lua_pushstring(_lua, "green"); lua_pushnumber(_lua, colour[1]); lua_settable(_lua, -3); lua_pushstring(_lua, "blue"); lua_pushnumber(_lua, colour[2]); lua_settable(_lua, -3); return 1; } case(GL_RGBA): { lua_newtable(_lua); luaL_getmetatable(_lua, "LuaScriptEngine.Table"); lua_setmetatable(_lua, -2); lua_pushstring(_lua, "red"); lua_pushnumber(_lua, colour[0]); lua_settable(_lua, -3); lua_pushstring(_lua, "green"); lua_pushnumber(_lua, colour[1]); lua_settable(_lua, -3); lua_pushstring(_lua, "blue"); lua_pushnumber(_lua, colour[2]); lua_settable(_lua, -3); lua_pushstring(_lua, "alpha"); lua_pushnumber(_lua, colour[3]); lua_settable(_lua, -3); return 1; } case(GL_BGR): { lua_newtable(_lua); luaL_getmetatable(_lua, "LuaScriptEngine.Table"); lua_setmetatable(_lua, -2); lua_pushstring(_lua, "red"); lua_pushnumber(_lua, colour[2]); lua_settable(_lua, -3); lua_pushstring(_lua, "green"); lua_pushnumber(_lua, colour[1]); lua_settable(_lua, -3); lua_pushstring(_lua, "blue"); lua_pushnumber(_lua, colour[0]); lua_settable(_lua, -3); return 1; } case(GL_BGRA): { lua_newtable(_lua); luaL_getmetatable(_lua, "LuaScriptEngine.Table"); lua_setmetatable(_lua, -2); lua_pushstring(_lua, "red"); lua_pushnumber(_lua, colour[2]); lua_settable(_lua, -3); lua_pushstring(_lua, "green"); lua_pushnumber(_lua, colour[1]); lua_settable(_lua, -3); lua_pushstring(_lua, "blue"); lua_pushnumber(_lua, colour[0]); lua_settable(_lua, -3); lua_pushstring(_lua, "alpha"); lua_pushnumber(_lua, colour[3]); lua_settable(_lua, -3); return 1; } } OSG_NOTICE<<"Warning: Image:get() unsupported PixelFormat"<=image->s() || j>=image->t() || k>=image->r()) { OSG_NOTICE<<"Warning: Image::set("<data(i,j,k); unsigned int numComponents = osg::Image::computeNumComponents(image->getPixelFormat()); switch(image->getDataType()) { case(GL_BYTE): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_UNSIGNED_BYTE): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_SHORT): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_UNSIGNED_SHORT): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_INT): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_UNSIGNED_INT): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_FLOAT): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; case(GL_DOUBLE): for(unsigned int i=0; i(ptr)+i) = static_cast(colourToWrite[i]); } break; default: OSG_NOTICE<<"Warning: Unsupported DataType in Image::set()"<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<2 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Image* image = lse->getObjectFromTable(1); if (!image) { OSG_NOTICE<<"Warning: Image:set() can only be called on a Image"<=3 && lua_isnumber(_lua, 2)) { i = static_cast(lua_tonumber(_lua, 2)); positionSet = true; } if (n>=4 && lua_isnumber(_lua, 3)) { j = static_cast(lua_tonumber(_lua, 3)); positionSet = true; } if (n>=5 && lua_isnumber(_lua, 4)) { k = static_cast(lua_tonumber(_lua, 4)); positionSet = true; } osg::Vec4d colour(1.0,1.0,1.0,1.0); if (lua_isnumber(_lua, n)) { colour[0] = colour[1] = colour[2] = colour[3] = lua_tonumber(_lua, n); } else if (lua_istable(_lua, n)) { lua_getfield(_lua, n, "intensity"); if (lua_isnumber(_lua, -1)) { double i = lua_tonumber(_lua, -1); colour[0] = i; colour[1] = i; colour[2] = i; colour[3] = i; } lua_pop(_lua, 1); lua_getfield(_lua, n, "i"); if (lua_isnumber(_lua, -1)) { double i = lua_tonumber(_lua, -1); colour[0] = i; colour[1] = i; colour[2] = i; colour[3] = i; } lua_pop(_lua, 1); lua_getfield(_lua, n, "luminance"); if (lua_isnumber(_lua, -1)) { double l = lua_tonumber(_lua, -1); colour[0] = l; colour[1] = l; colour[2] = l; } lua_pop(_lua, 1); lua_getfield(_lua, n, "l"); if (lua_isnumber(_lua, -1)) { double l = lua_tonumber(_lua, -1); colour[0] = l; colour[1] = l; colour[2] = l; } lua_pop(_lua, 1); lua_getfield(_lua, n, "alpha"); if (lua_isnumber(_lua, -1)) { double a = lua_tonumber(_lua, -1); colour[3] = a; } lua_pop(_lua, 1); lua_getfield(_lua, n, "a"); if (lua_isnumber(_lua, -1)) { double a = lua_tonumber(_lua, -1); colour[3] = a; } lua_pop(_lua, 1); lua_getfield(_lua, n, "red"); if (lua_isnumber(_lua, -1)) { double r = lua_tonumber(_lua, -1); colour[0] = r; } lua_pop(_lua, 1); lua_getfield(_lua, n, "r"); if (lua_isnumber(_lua, -1)) { double r = lua_tonumber(_lua, -1); colour[0] = r; } lua_pop(_lua, 1); lua_getfield(_lua, n, "green"); if (lua_isnumber(_lua, -1)) { double g = lua_tonumber(_lua, -1); colour[1] = g; } lua_pop(_lua, 1); lua_getfield(_lua, n, "g"); if (lua_isnumber(_lua, -1)) { double g = lua_tonumber(_lua, -1); colour[1] = g; } lua_pop(_lua, 1); lua_getfield(_lua, n, "blue"); if (lua_isnumber(_lua, -1)) { double b = lua_tonumber(_lua, -1); colour[2] = b; } lua_pop(_lua, 1); lua_getfield(_lua, n, "b"); if (lua_isnumber(_lua, -1)) { double b = lua_tonumber(_lua, -1); colour[2] = b; } lua_pop(_lua, 1); } // repack the colour data to the final destination form osg::Vec4d colourToWrite = colour; switch(image->getPixelFormat()) { case(GL_INTENSITY): colourToWrite[0] = colour[0]; break; case(GL_LUMINANCE): colourToWrite[0] = colour[0]; break; case(GL_ALPHA): colourToWrite[0] = colour[3]; break; case(GL_LUMINANCE_ALPHA): { colourToWrite[0] = colour[0]; colourToWrite[1] = colour[3]; break; } case(GL_RGB): case(GL_RGBA): { // nothing to do as data is already in the correct form break; } case(GL_BGR): case(GL_BGRA): { colourToWrite[0] = colour[2]; colourToWrite[1] = colour[1]; colourToWrite[2] = colour[0]; colourToWrite[3] = colour[3]; return 1; } } if (positionSet) { setImageColour(image, i,j,k, colourToWrite); } else { for(k=0; kr(); ++k) { for(j=0; jt(); ++j) { for(i=0; is(); ++i) { setImageColour(image, i,j,k, colourToWrite); } } } } return 0; } ////////////////////////////////////////////////////////////////////////////////////// // // Node Parent // static int callGetParent(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Node* node = lse->getObjectFromTable(1); if (!node) { OSG_NOTICE<<"Warning: Node::getParent() can only be called on a Node"<=2 && lua_isnumber(_lua, 2)) { index = static_cast(lua_tonumber(_lua, 2)); if (index>=0 && index(node->getNumParents())) { lse->pushObject(node->getParent(0)); return 1; } else { OSG_NOTICE<<"Warning: Call to node:getParent(index) has an out of range index."<(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n<1 || lua_type(_lua, 1)!=LUA_TTABLE) return 0; osg::Node* node = lse->getObjectFromTable(1); if (!node) { OSG_NOTICE<<"Warning: Node::getNumParents() can only be called on a Node"<getNumParents()); return 1; } ////////////////////////////////////////////////////////////////////////////////////// // // Method calling support // static int callClassMethod(lua_State* _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); std::string methodName = lua_tostring(_lua, lua_upvalueindex(2)); int n = lua_gettop(_lua); /* number of arguments */ if (n>=1 && lua_type(_lua, 1)==LUA_TTABLE) { osg::Object* object = lse->getObjectFromTable(1); const std::string compoundClassName = lse->getObjectCompoundClassName(1); // object->getCompoundClassName(); // OSG_NOTICE<<"callClassMethod() on "<className()<<" method name "<popParameterObject()); } if (lse->getClassInterface().run(object, compoundClassName, methodName, inputParameters, outputParameters)) { for(osg::Parameters::iterator itr = outputParameters.begin(); itr != outputParameters.end(); ++itr) { // OSG_NOTICE<<" pushing return "<<(*itr)->className()<pushParameter(itr->get()); } return outputParameters.size(); } } else { OSG_NOTICE<<"Warning: lua method called without passing object, use object::method() convention."<(reinterpret_cast(lua_touserdata(_lua, 1))); object->unref(); } } return 0; } static int newObject(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==1) { if (lua_type(_lua, 1)==LUA_TSTRING) { std::string compoundName = lua_tostring(_lua, 1); lse->createAndPushObject(compoundName); return 1; } } return 0; } static int castObject(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==2) { if (lua_type(_lua, 1)==LUA_TSTRING && lua_type(_lua, 2)==LUA_TTABLE) { std::string new_compoundClassName = lua_tostring(_lua, 1); osg::Object* object = lse->getObjectFromTable(2); lse->pushAndCastObject(new_compoundClassName, object); return 1; } } return 0; } static int readObjectFile(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==1 && lua_type(_lua, 1)==LUA_TSTRING) { std::string filename = lua_tostring(_lua, 1); osg::ref_ptr object = osgDB::readRefObjectFile(filename); if (object.valid()) { lse->pushObject(object.get()); return 1; } } return 0; } static int readImageFile(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==1 && lua_type(_lua, 1)==LUA_TSTRING) { std::string filename = lua_tostring(_lua, 1); osg::ref_ptr image = osgDB::readRefImageFile(filename); if (image.valid()) { lse->pushObject(image.get()); return 1; } } return 0; } static int readNodeFile(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n==1 && lua_type(_lua, 1)==LUA_TSTRING) { std::string filename = lua_tostring(_lua, 1); osg::ref_ptr node = osgDB::readRefNodeFile(filename); if (node.valid()) { lse->pushObject(node.get()); return 1; } } return 0; } static int writeFile(lua_State * _lua) { const LuaScriptEngine* lse = reinterpret_cast(lua_topointer(_lua, lua_upvalueindex(1))); int n = lua_gettop(_lua); /* number of arguments */ if (n>=2 && lua_type(_lua, 1)==LUA_TTABLE && lua_type(_lua, 2)==LUA_TSTRING) { osg::Object* object = lse->getObjectFromTable(1); std::string filename = lua_tostring(_lua, 2); if (object) { osgDB::writeObjectFile(*object, filename); return 1; } } return 0; } LuaScriptEngine::LuaScriptEngine(): osg::ScriptEngine("lua"), _lua(0), _scriptCount(0) { initialize(); } LuaScriptEngine::LuaScriptEngine(const LuaScriptEngine& rhs, const osg::CopyOp&): osg::ScriptEngine("lua"), _lua(0), _scriptCount(0) { initialize(); } LuaScriptEngine::~LuaScriptEngine() { lua_close(_lua); } std::string LuaScriptEngine::createUniquieScriptName() { std::stringstream sstr; sstr<<"script_"<<_scriptCount; ++_scriptCount; return sstr.str(); } void LuaScriptEngine::initialize() { _lua = luaL_newstate(); luaL_openlibs(_lua); // provide global new method for creating osg::Object's. { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, newObject, 1); lua_setglobal(_lua, "new"); } // provide global new method for casting osg::Object's. { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, castObject, 1); lua_setglobal(_lua, "cast"); } // provide global new method for reading Objects { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, readObjectFile, 1); lua_setglobal(_lua, "readFile"); } // provide global new method for reading Objects { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, readObjectFile, 1); lua_setglobal(_lua, "readObjectFile"); } // provide global new method for reading Nodes { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, readNodeFile, 1); lua_setglobal(_lua, "readNodeFile"); } // provide global new method for read Images { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, readImageFile, 1); lua_setglobal(_lua, "readImageFile"); } // provide global new method for read Images { lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, writeFile, 1); lua_setglobal(_lua, "writeFile"); } // Set up the __newindex and __index methods for looking up implementations of Object properties { luaL_newmetatable(_lua, "LuaScriptEngine.Object"); lua_pushstring(_lua, "__index"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, getProperty, 1); lua_settable(_lua, -3); lua_pushstring(_lua, "__newindex"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, setProperty, 1); lua_settable(_lua, -3); lua_pushstring(_lua, "__tostring"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, tostring, 1); lua_settable(_lua, -3); lua_pop(_lua,1); } // Set up the __tostring methods to be able to convert tables into strings so they can be output for debugging purposes. { luaL_newmetatable(_lua, "LuaScriptEngine.Table"); lua_pushstring(_lua, "__tostring"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, tostring, 1); lua_settable(_lua, -3); lua_pop(_lua,1); } // Set up the __newindex and __index methods for looking up implementations of Object properties { luaL_newmetatable(_lua, "LuaScriptEngine.Container"); lua_pushstring(_lua, "__index"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, getContainerProperty, 1); lua_settable(_lua, -3); lua_pushstring(_lua, "__newindex"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, setContainerProperty, 1); lua_settable(_lua, -3); lua_pop(_lua,1); } // Set up the __newindex and __index methods for looking up implementations of Object properties { luaL_newmetatable(_lua, "LuaScriptEngine.Map"); lua_pushstring(_lua, "__index"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, getMapProperty, 1); lua_settable(_lua, -3); lua_pushstring(_lua, "__newindex"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, setMapProperty, 1); lua_settable(_lua, -3); lua_pop(_lua,1); } // Set up the __gc methods for looking up implementations of Object pointer to do the unref when the associated Lua object is destroyed. { luaL_newmetatable(_lua, "LuaScriptEngine.UnrefObject"); lua_pushstring(_lua, "__gc"); lua_pushlightuserdata(_lua, this); lua_pushcclosure(_lua, garabageCollectObject, 1); lua_settable(_lua, -3); lua_pop(_lua,1); } } bool LuaScriptEngine::loadScript(osg::Script* script) { if (_loadedScripts.count(script)!=0) return true; int loadResult = luaL_loadstring(_lua, script->getScript().c_str()); if (loadResult==0) { std::string scriptID = createUniquieScriptName(); lua_pushvalue(_lua, -1); lua_setglobal(_lua, scriptID.c_str()); _loadedScripts[script] = scriptID; return true; } else { OSG_NOTICE << "LuaScriptEngine::luaL_loadstring(Script*) error: " << lua_tostring(_lua, -1) << std::endl; return false; } } bool LuaScriptEngine::run(osg::Script* script, const std::string& entryPoint, osg::Parameters& inputParameters, osg::Parameters& outputParameters) { if (!script || !_lua) return false; if (_loadedScripts.count(script)==0) { if (!loadScript(script)) return false; if (!entryPoint.empty()) { if (lua_pcall(_lua, 0, 0, 0)!=0) { OSG_NOTICE<< "error initialize script "<< lua_tostring(_lua, -1)<second; lua_getglobal(_lua, scriptID.c_str()); } else { lua_getglobal(_lua, entryPoint.c_str()); /* function to be called */ } for(osg::Parameters::const_iterator itr = inputParameters.begin(); itr != inputParameters.end(); ++itr) { pushParameter(itr->get()); } if (lua_pcall(_lua, inputParameters.size(), LUA_MULTRET,0)!=0) { OSG_NOTICE<<"Lua error : "< obj = popParameterObject(); if (obj.valid()) outputParameters.push_back(obj); } return true; } class PushStackValueVisitor : public osg::ValueObject::GetValueVisitor { public: const LuaScriptEngine* _lse; lua_State* _lua; PushStackValueVisitor(const LuaScriptEngine* lse) : _lse(lse) { _lua = const_cast(lse)->getLuaState(); } virtual void apply(bool value) { lua_pushboolean(_lua, value ? 1 : 0); } virtual void apply(char value) { lua_pushnumber(_lua, value); } virtual void apply(unsigned char value) { lua_pushnumber(_lua, value); } virtual void apply(short value) { lua_pushnumber(_lua, value); } virtual void apply(unsigned short value) { lua_pushnumber(_lua, value); } virtual void apply(int value) { lua_pushnumber(_lua, value); } virtual void apply(unsigned int value) { lua_pushnumber(_lua, value); } virtual void apply(float value) { lua_pushnumber(_lua, value); } virtual void apply(double value) { lua_pushnumber(_lua, value); } virtual void apply(const std::string& value) { lua_pushlstring(_lua, &value[0], value.size()); } virtual void apply(const osg::Vec2f& value) { _lse->pushValue(value); } virtual void apply(const osg::Vec3f& value) { _lse->pushValue(value); } virtual void apply(const osg::Vec4f& value) { _lse->pushValue(value); } virtual void apply(const osg::Vec2d& value) { _lse->pushValue(value); } virtual void apply(const osg::Vec3d& value) { _lse->pushValue(value); } virtual void apply(const osg::Vec4d& value) { _lse->pushValue(value); } virtual void apply(const osg::Quat& value) { _lse->pushValue(value); } virtual void apply(const osg::Plane& value) { _lse->pushValue(value); } virtual void apply(const osg::Matrixf& value) { _lse->pushValue(value); } virtual void apply(const osg::Matrixd& value) { _lse->pushValue(value); } }; #if LUA_VERSION_NUM<=501 #define lua_rawlen lua_strlen #endif class GetStackValueVisitor : public osg::ValueObject::SetValueVisitor { public: const LuaScriptEngine* _lse; lua_State* _lua; int _index; int _numberToPop; GetStackValueVisitor(const LuaScriptEngine* lse, int index) : _lse(lse), _lua(0), _index(index), _numberToPop(0) { _lua = const_cast(lse )->getLuaState(); } virtual void apply(bool& value) { if (lua_isboolean(_lua, _index)) { value = (lua_toboolean(_lua, _index)!=0); _numberToPop = 1; } } virtual void apply(char& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(unsigned char& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(short& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(unsigned short& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(int& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(unsigned int& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(float& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(double& value) { if (lua_isnumber(_lua, _index)) { value = lua_tonumber(_lua, _index)!=0; _numberToPop = 1; } } virtual void apply(std::string& value) { if (lua_isstring(_lua, _index)) { value = std::string(lua_tostring(_lua, _index), lua_rawlen(_lua, _index)); _numberToPop = 1; } } virtual void apply(osg::Vec2f& value) { _lse->getValue(_index, value); _numberToPop = 2;} virtual void apply(osg::Vec3f& value) { _lse->getValue(_index, value); _numberToPop = 2; } virtual void apply(osg::Vec4f& value) { _lse->getValue(_index, value); _numberToPop = 4; } virtual void apply(osg::Vec2d& value) { _lse->getValue(_index, value); _numberToPop = 2; } virtual void apply(osg::Vec3d& value) { _lse->getValue(_index, value); _numberToPop = 3; } virtual void apply(osg::Vec4d& value) { _lse->getValue(_index, value); _numberToPop = 4; } virtual void apply(osg::Quat& value) { _lse->getValue(_index, value); _numberToPop = 4; } virtual void apply(osg::Plane& value) { _lse->getValue(_index, value); _numberToPop = 4; } virtual void apply(osg::Matrixf& value) { _lse->getValue(_index, value); } virtual void apply(osg::Matrixd& value) { _lse->getValue(_index, value); } virtual void apply(osg::BoundingBoxf& value) { _lse->getValue(_index, value); } virtual void apply(osg::BoundingBoxd& value) { _lse->getValue(_index, value); } virtual void apply(osg::BoundingSpheref& value) { _lse->getValue(_index, value); } virtual void apply(osg::BoundingSphered& value) { _lse->getValue(_index, value); } }; int LuaScriptEngine::pushPropertyToStack(osg::Object* object, const std::string& propertyName) const { osgDB::BaseSerializer::Type type; if (!_ci.getPropertyType(object, propertyName, type)) { if (_ci.hasMethod(object, propertyName)) { lua_pushlightuserdata(_lua, const_cast(this)); lua_pushstring(_lua, propertyName.c_str()); lua_pushcclosure(_lua, callClassMethod, 2); return 1; } osg::Object* uo = osg::getUserObject(object, propertyName); LuaCallbackObject* lco = dynamic_cast(uo); if (lco) { lua_rawgeti(_lua, LUA_REGISTRYINDEX, lco->getRef()); return 1; } else if (uo) { pushObject(uo); return 1; } OSG_INFO<<"LuaScriptEngine::pushPropertyToStack("<getIntLookup() : 0; if (lookup) { std::string enumString = lookup->getString(value); lua_pushstring(_lua, enumString.c_str()); } else { lua_pushinteger(_lua, value); } return 1; } break; } case(osgDB::BaseSerializer::RW_SHORT): { short value; if (_ci.getProperty(object, propertyName, value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_USHORT): { unsigned short value; if (_ci.getProperty(object, propertyName, value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_INT): { int value; if (_ci.getProperty(object, propertyName, value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_UINT): { unsigned int value; if (_ci.getProperty(object, propertyName, value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_FLOAT): { float value; if (_ci.getProperty(object, propertyName, value)) { lua_pushnumber(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_DOUBLE): { double value; if (_ci.getProperty(object, propertyName, value)) { lua_pushnumber(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC2F): { osg::Vec2f value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC3F): { osg::Vec3f value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC4F): { osg::Vec4f value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC2D): { osg::Vec2d value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC3D): { osg::Vec3d value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC4D): { osg::Vec4d value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } #ifdef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXF): { osg::Matrixf value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } #ifndef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXD): { osg::Matrixd value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXF): { osg::BoundingBoxf value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXD): { osg::BoundingBoxd value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHEREF): { osg::BoundingSpheref value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHERED): { osg::BoundingSphered value; if (_ci.getProperty(object, propertyName, value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_LIST): { OSG_NOTICE<<"Need to implement RW_LIST support"<getObjectWrapperManager(); { const osgDB::IntLookup& lookup = ow->getLookupMap()["GL"]; const osgDB::IntLookup::ValueToString& vts = lookup.getValueToString(); osgDB::IntLookup::ValueToString::const_iterator itr = vts.find(value); if (itr!=vts.end()) return itr->second; } { const osgDB::IntLookup& lookup = ow->getLookupMap()["PrimitiveType"]; const osgDB::IntLookup::ValueToString& vts = lookup.getValueToString(); osgDB::IntLookup::ValueToString::const_iterator itr = vts.find(value); if (itr!=vts.end()) return itr->second; } OSG_NOTICE<<"Warning: LuaScriptEngine did not find valid GL enum value for GLenum value: "<getObjectWrapperManager(); { const osgDB::IntLookup& lookup = ow->getLookupMap()["GL"]; const osgDB::IntLookup::StringToValue& stv = lookup.getStringToValue(); osgDB::IntLookup::StringToValue::const_iterator itr = stv.find(str); if (itr!=stv.end()) return itr->second; } { const osgDB::IntLookup& lookup = ow->getLookupMap()["PrimitiveType"]; const osgDB::IntLookup::StringToValue& stv = lookup.getStringToValue(); osgDB::IntLookup::StringToValue::const_iterator itr = stv.find(str); if (itr!=stv.end()) return itr->second; } OSG_NOTICE<<"Warning: LuaScriptEngine did not find valid GL enum value for string value: "<dataType) { case(osgDB::BaseSerializer::RW_BOOL): { bool value; if (ssp->get(value)) { lua_pushboolean(_lua, value ? 1 : 0); return 1; } break; } case(osgDB::BaseSerializer::RW_STRING): { std::string value; if (ssp->get(value)) { lua_pushstring(_lua, value.c_str()); return 1; } break; } case(osgDB::BaseSerializer::RW_GLENUM): { GLenum value; if (ssp->get(value)) { std::string enumString = lookUpGLenumString(value); lua_pushstring(_lua, enumString.c_str()); return 1; } break; } case(osgDB::BaseSerializer::RW_ENUM): { int value; if (ssp->get(value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_INT): { int value; if (ssp->get(value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_UINT): { unsigned int value; if (ssp->get(value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_SHORT): { short value; if (ssp->get(value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_USHORT): { unsigned short value; if (ssp->get(value)) { lua_pushinteger(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_FLOAT): { float value; if (ssp->get(value)) { lua_pushnumber(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_DOUBLE): { double value; if (ssp->get(value)) { lua_pushnumber(_lua, value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC2F): { osg::Vec2f value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC3F): { osg::Vec3f value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC4F): { osg::Vec4f value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC2D): { osg::Vec2d value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC3D): { osg::Vec3d value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_VEC4D): { osg::Vec4d value; if (ssp->get(value)) { pushValue(value); return 1; } break; } #ifdef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXF): { osg::Matrixf value; if (ssp->get(value)) { pushValue(value); return 1; } break; } #ifndef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXD): { osg::Matrixd value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXF): { osg::BoundingBoxf value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXD): { osg::BoundingBoxd value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHEREF): { osg::BoundingSpheref value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHERED): { osg::BoundingSphered value; if (ssp->get(value)) { pushValue(value); return 1; } break; } case(osgDB::BaseSerializer::RW_IMAGE): case(osgDB::BaseSerializer::RW_OBJECT): { osg::Object* value = 0; if (ssp->get(value)) { pushObject(value); return 1; } break; } case(osgDB::BaseSerializer::RW_LIST): { break; } case(osgDB::BaseSerializer::RW_VECTOR): { break; } default: break; } OSG_NOTICE<<"LuaScriptEngine::pushDataToStack() property of type = "<<_ci.getTypeName(ssp->dataType)<<" error, not supported."<set(static_cast(lua_toboolean(_lua, pos)!=0)); return 0; } else if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos)!=0)); return 0; } break; } case(osgDB::BaseSerializer::RW_STRING): { if (lua_isstring(_lua, pos)) { ssp->set(std::string(lua_tostring(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_GLENUM): { if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos))); return 0; } else if (lua_isstring(_lua, pos)) { const char* enumString = lua_tostring(_lua, pos); GLenum value = lookUpGLenumValue(enumString); //getValue("GL",enumString); ssp->set(value); return 0; } OSG_NOTICE<<"LuaScriptEngine::getDataFromStack() osgDB::BaseSerializer::RW_GLENUM Failed"<set(static_cast(lua_tonumber(_lua, pos))); return 0; } else if (lua_isstring(_lua, pos)) { OSG_NOTICE<<"LuaScriptEngine::getDataFromStack() osgDB::BaseSerializer::RW_ENUM Failed to convert string"<set(static_cast(lua_tonumber(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_USHORT): { if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_INT): { if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_UINT): { if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_FLOAT): { if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_DOUBLE): { if (lua_isnumber(_lua, pos)) { ssp->set(static_cast(lua_tonumber(_lua, pos))); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC2F): { osg::Vec2f value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC3F): { osg::Vec3f value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC4F): { osg::Vec4f value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC2D): { osg::Vec2d value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC3D): { osg::Vec3d value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC4D): { osg::Vec4d value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_QUAT): { osg::Quat value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_PLANE): { osg::Plane value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } #ifdef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXF): { osg::Matrixd value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } #ifndef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXD): { osg::Matrixd value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXF): { osg::BoundingBoxf value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXD): { osg::BoundingBoxd value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHEREF): { osg::BoundingSpheref value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHERED): { osg::BoundingSphered value; if (getValue(pos, value)) { ssp->set(value); return 0; } break; } case(osgDB::BaseSerializer::RW_LIST): { OSG_NOTICE<<"Need to implement RW_LIST support"<(reinterpret_cast(lua_touserdata(_lua,-1))); lua_pop(_lua, 1); if (value) { ssp->set(value); return 0; } else { OSG_NOTICE<<"Error: lua type '"<set(value); return 0; } else { OSG_NOTICE<<"Error: lua type '"< lco = new LuaCallbackObject(propertyName, this, ref); osg::UserDataContainer* udc = object->getOrCreateUserDataContainer(); unsigned int objectIndex = udc->getUserObjectIndex(propertyName); if (objectIndex < udc->getNumUserObjects()) { udc->setUserObject(objectIndex, lco.get()); } else { udc->addUserObject(lco.get()); } return 0; } type = LuaScriptEngine::getType(-1); } return setPropertyFromStack(object, propertyName, type); } int LuaScriptEngine::setPropertyFromStack(osg::Object* object, const std::string& propertyName, osgDB::BaseSerializer::Type type) const { switch(type) { case(osgDB::BaseSerializer::RW_BOOL): { if (lua_isboolean(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_toboolean(_lua, -1)!=0)); return 0; } else if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1)!=0)); return 0; } break; } case(osgDB::BaseSerializer::RW_STRING): { if (lua_isstring(_lua, -1)) { _ci.setProperty(object, propertyName, std::string(lua_tostring(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_GLENUM): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } else if (lua_isstring(_lua, -1)) { const char* enumString = lua_tostring(_lua, -1); GLenum value = lookUpGLenumValue(enumString); //getValue("GL",enumString); _ci.setProperty(object, propertyName, value); return 0; } OSG_NOTICE<<"LuaScriptEngine::setPropertyFromStack("<(lua_tonumber(_lua, -1))); return 0; } else if (lua_isstring(_lua, -1)) { const char* enumString = lua_tostring(_lua, -1); osgDB::BaseSerializer* serializer = _ci.getSerializer(object, propertyName, type); osgDB::IntLookup* lookup = serializer ? serializer->getIntLookup() : 0; if (lookup) { int value = lookup->getValue(enumString); _ci.setProperty(object, propertyName, value); } return 0; } break; } case(osgDB::BaseSerializer::RW_SHORT): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_USHORT): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_INT): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_UINT): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_FLOAT): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_DOUBLE): { if (lua_isnumber(_lua, -1)) { _ci.setProperty(object, propertyName, static_cast(lua_tonumber(_lua, -1))); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC2F): { osg::Vec2f value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC3F): { osg::Vec3f value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC4F): { osg::Vec4f value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC2D): { osg::Vec2d value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC3D): { osg::Vec3d value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_VEC4D): { osg::Vec4d value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_QUAT): { osg::Quat value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_PLANE): { osg::Plane value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } #ifdef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXF): { osg::Matrixd value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } #ifndef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXD): { osg::Matrixd value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXF): { osg::BoundingBoxf value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXD): { osg::BoundingBoxd value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHEREF): { osg::BoundingSpheref value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHERED): { osg::BoundingSphered value; if (getValue(-1, value)) { _ci.setProperty(object, propertyName, value); return 0; } break; } case(osgDB::BaseSerializer::RW_IMAGE): case(osgDB::BaseSerializer::RW_OBJECT): { if (lua_istable(_lua, -1)) { osg::Object* value = 0; lua_pushstring(_lua, "object_ptr"); lua_rawget(_lua, -2); if (lua_type(_lua, -1)==LUA_TUSERDATA) value = *const_cast(reinterpret_cast(lua_touserdata(_lua,-1))); lua_pop(_lua, 1); if (value) { _ci.setProperty(object, propertyName, value); return 0; } else { OSG_NOTICE<<"Error: lua type '"<className()<<"::"<className()<<"::"<className()<<"::"<(object); if (vo) { PushStackValueVisitor pvv(this); vo->get(pvv); } else { pushObject( object); } return false; } bool LuaScriptEngine::popParameter(osg::Object* object) const { osg::ValueObject* vo = dynamic_cast(object); if (vo) { GetStackValueVisitor pvv(this, -1); vo->set(pvv); lua_pop(_lua, pvv._numberToPop); } else { lua_pop(_lua, 1); } return false; } osg::Object* LuaScriptEngine::popParameterObject() const { osg::ref_ptr object = 0; osgDB::BaseSerializer::Type type = getType(-1); switch(type) { case(osgDB::BaseSerializer::RW_BOOL): { if (lua_isboolean(_lua, -1)) object = new osg::BoolValueObject("", lua_toboolean(_lua, -1)!=0); break; } case(osgDB::BaseSerializer::RW_STRING): { if (lua_isstring(_lua, -1)) object = new osg::StringValueObject("", lua_tostring(_lua, -1)); break; } case(osgDB::BaseSerializer::RW_GLENUM): case(osgDB::BaseSerializer::RW_ENUM): if (lua_isstring(_lua, -1)) { object = new osg::StringValueObject("", lua_tostring(_lua, -1)); } else if (lua_isnumber(_lua, -1)) { object = new osg::IntValueObject("", static_cast(lua_tonumber(_lua, -1))); } break; case(osgDB::BaseSerializer::RW_INT): { if (lua_isnumber(_lua, -1)) object = new osg::IntValueObject("", static_cast(lua_tonumber(_lua, -1))); break; } case(osgDB::BaseSerializer::RW_UINT): { if (lua_isnumber(_lua, -1)) object = new osg::UIntValueObject("", static_cast(lua_tonumber(_lua, -1))); break; } case(osgDB::BaseSerializer::RW_FLOAT): { if (lua_isnumber(_lua, -1)) object = new osg::FloatValueObject("", static_cast(lua_tonumber(_lua, -1))); break; } case(osgDB::BaseSerializer::RW_DOUBLE): { if (lua_isnumber(_lua, -1)) object = new osg::DoubleValueObject("", static_cast(lua_tonumber(_lua, -1))); break; } case(osgDB::BaseSerializer::RW_VEC2F): { osg::Vec2f value; if (getValue(-1, value)) object = new osg::Vec2fValueObject("", value); break; } case(osgDB::BaseSerializer::RW_VEC3F): { osg::Vec3f value; if (getValue(-1, value)) object = new osg::Vec3fValueObject("", value); break; } case(osgDB::BaseSerializer::RW_VEC4F): { osg::Vec4f value; if (getValue(-1, value)) object = new osg::Vec4fValueObject("", value); break; } #ifdef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXF): { osg::Matrixf value; if (getValue(-1, value)) object = new osg::MatrixfValueObject("", value); break; } case(osgDB::BaseSerializer::RW_VEC2D): { osg::Vec2d value; if (getValue(-1, value)) object = new osg::Vec2dValueObject("", value); break; } case(osgDB::BaseSerializer::RW_VEC3D): { osg::Vec3d value; if (getValue(-1, value)) object = new osg::Vec3dValueObject("", value); break; } case(osgDB::BaseSerializer::RW_VEC4D): { osg::Vec4d value; if (getValue(-1, value)) object = new osg::Vec4dValueObject("", value); break; } case(osgDB::BaseSerializer::RW_QUAT): { osg::Quat value; if (getValue(-1, value)) object = new osg::QuatValueObject("", value); break; } case(osgDB::BaseSerializer::RW_PLANE): { osg::Plane value; if (getValue(-1, value)) object = new osg::PlaneValueObject("", value); break; } #ifndef OSG_USE_FLOAT_MATRIX case(osgDB::BaseSerializer::RW_MATRIX): #endif case(osgDB::BaseSerializer::RW_MATRIXD): { osg::Matrixd value; if (getValue(-1, value)) object = new osg::MatrixdValueObject("", value); break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXF): { osg::BoundingBoxf value; if (getValue(-1, value)) object = new osg::BoundingBoxfValueObject("", value); break; } case(osgDB::BaseSerializer::RW_BOUNDINGBOXD): { osg::BoundingBoxd value; if (getValue(-1, value)) object = new osg::BoundingBoxdValueObject("", value); break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHEREF): { osg::BoundingSpheref value; if (getValue(-1, value)) object = new osg::BoundingSpherefValueObject("", value); break; } case(osgDB::BaseSerializer::RW_BOUNDINGSPHERED): { osg::BoundingSphered value; if (getValue(-1, value)) object = new osg::BoundingSpheredValueObject("", value); break; } case(osgDB::BaseSerializer::RW_LIST): { OSG_NOTICE<<"Need to implement RW_LIST support"<(reinterpret_cast(lua_touserdata(_lua,-1))); } lua_pop(_lua, 1); } default: break; } lua_pop(_lua, 1); return object.release(); #if 0 osg::ValueObject* vo = dynamic_cast(object); if (vo) { GetStackValueVisitor pvv(this, -1); vo->set(pvv); lua_pop(_lua, pvv._numberToPop); } else { lua_pop(_lua, 1); } #endif return object.release(); } void LuaScriptEngine::pushContainer(osg::Object* object, const std::string& propertyName) const { if (object) { lua_newtable(_lua); // set up objbect_ptr to handle ref/unref of the object { lua_pushstring(_lua, "object_ptr"); // create user data for pointer void* userdata = lua_newuserdata( _lua, sizeof(osg::Object*)); (*reinterpret_cast(userdata)) = object; luaL_getmetatable( _lua, "LuaScriptEngine.UnrefObject"); lua_setmetatable( _lua, -2 ); lua_settable(_lua, -3); // increment the reference count as the lua now will unreference it once it's finished with the userdata for the pointer object->ref(); } lua_pushstring(_lua, "containerPropertyName"); lua_pushstring(_lua, propertyName.c_str()); lua_settable(_lua, -3); osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* bs = _ci.getSerializer(object, propertyName, type); osgDB::VectorBaseSerializer* vs = dynamic_cast(bs); osgDB::MapBaseSerializer* ms = dynamic_cast(bs); if (vs) { assignClosure("size", getContainerSize); assignClosure("clear", callVectorClear); assignClosure("resize", callVectorResize); assignClosure("reserve", callVectorReserve); assignClosure("add", callVectorAdd); luaL_getmetatable(_lua, "LuaScriptEngine.Container"); lua_setmetatable(_lua, -2); } else if (ms) { assignClosure("clear", callMapClear); assignClosure("size", getMapSize); assignClosure("createIterator", createMapIterator); assignClosure("createReverseIterator", createMapReverseIterator); luaL_getmetatable(_lua, "LuaScriptEngine.Map"); lua_setmetatable(_lua, -2); } else { OSG_NOTICE<<"Container type not suppported."< object = _ci.createObject(compoundName); if (!object) OSG_NOTICE<<"Failed to create object "<(userdata)) = object; luaL_getmetatable( _lua, "LuaScriptEngine.UnrefObject"); lua_setmetatable( _lua, -2 ); lua_settable(_lua, -3); // increment the reference count as the lua now will unreference it once it's finished with the userdata for the pointer object->ref(); } lua_pushstring(_lua, "libraryName"); lua_pushstring(_lua, object->libraryName()); lua_settable(_lua, -3); lua_pushstring(_lua, "className"); lua_pushstring(_lua, object->className()); lua_settable(_lua, -3); lua_pushstring(_lua, "compoundClassName"); lua_pushstring(_lua, object->getCompoundClassName().c_str()); lua_settable(_lua, -3); // check to see if Object "is a" vector osgDB::BaseSerializer::Type type; osgDB::BaseSerializer* vs = _ci.getSerializer(object, "vector", type); if (vs) { lua_pushstring(_lua, "containerPropertyName"); lua_pushstring(_lua, "vector"); lua_settable(_lua, -3); assignClosure("size", getContainerSize); assignClosure("clear", callVectorClear); assignClosure("resize", callVectorResize); assignClosure("reserve", callVectorReserve); assignClosure("add", callVectorAdd); luaL_getmetatable(_lua, "LuaScriptEngine.Container"); lua_setmetatable(_lua, -2); } else if (dynamic_cast(object)!=0) { assignClosure("advance", callMapIteratorAdvance); assignClosure("valid", callMapIteratorValid); assignClosure("getKey", getMapIteratorKey); assignClosure("getElement", getMapIteratorElement); assignClosure("setElement", setMapIteratorElement); } else if (dynamic_cast(object)!=0) { assignClosure("allocate", callImageAllocate); assignClosure("s", callImageS); assignClosure("t", callImageT); assignClosure("r", callImageR); assignClosure("get", callImageGet); assignClosure("set", callImageSet); luaL_getmetatable(_lua, "LuaScriptEngine.Object"); lua_setmetatable(_lua, -2); } else if (dynamic_cast(object)!=0) { assignClosure("add", callStateSetSet); assignClosure("set", callStateSetSet); assignClosure("get", callStateSetGet); assignClosure("remove", callStateSetRemove); luaL_getmetatable(_lua, "LuaScriptEngine.Object"); lua_setmetatable(_lua, -2); } else if (dynamic_cast(object)!=0) { assignClosure("getParent", callGetParent); assignClosure("getNumParents", callGetNumParents); luaL_getmetatable(_lua, "LuaScriptEngine.Object"); lua_setmetatable(_lua, -2); } else { luaL_getmetatable(_lua, "LuaScriptEngine.Object"); lua_setmetatable(_lua, -2); } } else { lua_pushnil(_lua); } } void LuaScriptEngine::pushAndCastObject(const std::string& compoundClassName, osg::Object* object) const { if (object && _ci.isObjectOfType(object, compoundClassName)) { lua_newtable(_lua); // set up objbect_ptr to handle ref/unref of the object { lua_pushstring(_lua, "object_ptr"); // create user data for pointer void* userdata = lua_newuserdata( _lua, sizeof(osg::Object*)); (*reinterpret_cast(userdata)) = object; luaL_getmetatable( _lua, "LuaScriptEngine.UnrefObject"); lua_setmetatable( _lua, -2 ); lua_settable(_lua, -3); // increment the reference count as the lua now will unreference it once it's finished with the userdata for the pointer object->ref(); } std::string::size_type seperator = compoundClassName.find("::"); std::string libraryName = (seperator==std::string::npos) ? object->libraryName() : compoundClassName.substr(0, seperator); std::string className = (seperator==std::string::npos) ? object->className() : compoundClassName.substr(seperator+2,std::string::npos); lua_pushstring(_lua, "libraryName"); lua_pushstring(_lua, libraryName.c_str()); lua_settable(_lua, -3); lua_pushstring(_lua, "className"); lua_pushstring(_lua, className.c_str()); lua_settable(_lua, -3); lua_pushstring(_lua, "compoundClassName"); lua_pushstring(_lua, compoundClassName.c_str()); lua_settable(_lua, -3); luaL_getmetatable(_lua, "LuaScriptEngine.Object"); lua_setmetatable(_lua, -2); } else { lua_pushnil(_lua); } } void LuaScriptEngine::assignClosure(const char* name, lua_CFunction fn) const { lua_pushstring(_lua, name); lua_pushlightuserdata(_lua, const_cast(this)); lua_pushcclosure(_lua, fn, 1); lua_settable(_lua, -3); } void LuaScriptEngine::addPaths(const osgDB::FilePathList& paths) { lua_getglobal( _lua, "package" ); lua_getfield( _lua, -1, "path" ); std::string path = lua_tostring( _lua, -1 ); lua_pop( _lua, 1 ); OSG_NOTICE<<"LuaScriptEngine::addPaths() original package.path = "<getDatabasePathList()); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/jpeg/0000755000175000017500000000000013151044751022730 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/jpeg/ReaderWriterJPEG.cpp0000644000175000017500000011311113151044751026477 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #if defined(_MSC_VER) && defined(OSG_DISABLE_MSVC_WARNINGS) // disable "structure was padded due to __declspec(align()) #pragma warning( disable : 4324 ) #endif /**************************************************************************** * * Follows is code extracted from the simage library. Original Authors: * * Systems in Motion, * * * Peder Blekken * Morten Eriksen * Marius Bugge Monsen * * The original COPYING notice * * All files in this library are public domain, except simage_rgb.cpp which is * Copyright (c) Mark J Kilgard . I will contact Mark * very soon to hear if this source also can become public domain. * * Please send patches for bugs and new features to: . * * Peder Blekken * * * Ported into the OSG as a plugin, Robert Osfield December 2000. * Note, reference above to license of simage_rgb is not relevant to the OSG * as the OSG does not use it. Also for patches, bugs and new features * please send them direct to the OSG dev team rather than address above. * **********************************************************************/ /* * Based on example code found in the libjpeg archive * */ #include "EXIF_Orientation.h" #include #include #include #include #if defined(_MSC_VER) && defined(OSG_DISABLE_MSVC_WARNINGS) #pragma warning( disable : 4611 ) #endif namespace osgDBJPEG { #define ERR_NO_ERROR 0 #define ERR_OPEN 1 #define ERR_MEM 2 #define ERR_JPEGLIB 3 static int jpegerror = ERR_NO_ERROR; /* Some versions of jmorecfg.h define boolean, some don't... Those that do also define HAVE_BOOLEAN, so we can guard using that. */ #ifndef HAVE_BOOLEAN typedef int boolean; #define FALSE 0 #define TRUE 1 #endif /* CODE FOR READING/WRITING JPEG FROM STREAMS * This code was taken directly from jdatasrc.c and jdatadst.c (libjpeg source) * and modified to use a std::istream/ostream* instead of a FILE* */ /* Expanded data source object for stdio input */ typedef struct { struct jpeg_source_mgr pub; /* public fields */ std::istream * infile; /* source stream */ JOCTET * buffer; /* start of buffer */ boolean start_of_file; /* have we gotten any data yet? */ } stream_source_mgr; typedef stream_source_mgr * stream_src_ptr; #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ /* * Initialize source --- called by jpeg_read_header * before any data is actually read. */ void init_source (j_decompress_ptr cinfo) { stream_src_ptr src = (stream_src_ptr) cinfo->src; /* We reset the empty-input-file flag for each image, * but we don't clear the input buffer. * This is correct behavior for reading a series of images from one source. */ src->start_of_file = TRUE; } /* * Fill the input buffer --- called whenever buffer is emptied. * * In typical applications, this should read fresh data into the buffer * (ignoring the current state of next_input_byte & bytes_in_buffer), * reset the pointer & count to the start of the buffer, and return TRUE * indicating that the buffer has been reloaded. It is not necessary to * fill the buffer entirely, only to obtain at least one more byte. * * There is no such thing as an EOF return. If the end of the file has been * reached, the routine has a choice of ERREXIT() or inserting fake data into * the buffer. In most cases, generating a warning message and inserting a * fake EOI marker is the best course of action --- this will allow the * decompressor to output however much of the image is there. However, * the resulting error message is misleading if the real problem is an empty * input file, so we handle that case specially. * * In applications that need to be able to suspend compression due to input * not being available yet, a FALSE return indicates that no more data can be * obtained right now, but more may be forthcoming later. In this situation, * the decompressor will return to its caller (with an indication of the * number of scanlines it has read, if any). The application should resume * decompression after it has loaded more data into the input buffer. Note * that there are substantial restrictions on the use of suspension --- see * the documentation. * * When suspending, the decompressor will back up to a convenient restart point * (typically the start of the current MCU). next_input_byte & bytes_in_buffer * indicate where the restart point will be if the current call returns FALSE. * Data beyond this point must be rescanned after resumption, so move it to * the front of the buffer rather than discarding it. */ boolean fill_input_buffer (j_decompress_ptr cinfo) { stream_src_ptr src = (stream_src_ptr) cinfo->src; size_t nbytes; src->infile->read((char*)src->buffer,INPUT_BUF_SIZE); nbytes = src->infile->gcount(); if (nbytes <= 0) { if (src->start_of_file) /* Treat empty input file as fatal error */ ERREXIT(cinfo, JERR_INPUT_EMPTY); WARNMS(cinfo, JWRN_JPEG_EOF); /* Insert a fake EOI marker */ src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2; } src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = nbytes; src->start_of_file = FALSE; return TRUE; } /* * Skip data --- used to skip over a potentially large amount of * uninteresting data (such as an APPn marker). * * Writers of suspendable-input applications must note that skip_input_data * is not granted the right to give a suspension return. If the skip extends * beyond the data currently in the buffer, the buffer can be marked empty so * that the next read will cause a fill_input_buffer call that can suspend. * Arranging for additional bytes to be discarded before reloading the input * buffer is the application writer's problem. */ void skip_input_data (j_decompress_ptr cinfo, long num_bytes) { stream_src_ptr src = (stream_src_ptr) cinfo->src; /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { while (num_bytes > (long) src->pub.bytes_in_buffer) { num_bytes -= (long) src->pub.bytes_in_buffer; (void) fill_input_buffer(cinfo); /* note we assume that fill_input_buffer will never return FALSE, * so suspension need not be handled. */ } src->pub.next_input_byte += (size_t) num_bytes; src->pub.bytes_in_buffer -= (size_t) num_bytes; } } /* * An additional method that can be provided by data source modules is the * resync_to_restart method for error recovery in the presence of RST markers. * For the moment, this source module just uses the default resync method * provided by the JPEG library. That method assumes that no backtracking * is possible. */ /* * Terminate source --- called by jpeg_finish_decompress * after all data has been read. Often a no-op. * * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding * application must deal with any cleanup that should happen even * for error exit. */ void term_source (j_decompress_ptr /*cinfo*/) { /* no work necessary here */ } void jpeg_istream_src(j_decompress_ptr cinfo, std::istream *infile) { stream_src_ptr src; /* The source object and input buffer are made permanent so that a series * of JPEG images can be read from the same file by calling jpeg_stdio_src * only before the first one. (If we discarded the buffer at the end of * one image, we'd likely lose the start of the next one.) * This makes it unsafe to use this manager and a different source * manager serially with the same JPEG object. Caveat programmer. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(stream_source_mgr)); src = (stream_src_ptr) cinfo->src; src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,INPUT_BUF_SIZE * sizeof(JOCTET)); } src = (stream_src_ptr) cinfo->src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = term_source; src->infile = infile; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ } /* Expanded data destination object for stdio output */ typedef struct { struct jpeg_destination_mgr pub; /* public fields */ std::ostream * outfile; /* target stream */ JOCTET * buffer; /* start of buffer */ } stream_destination_mgr; typedef stream_destination_mgr * stream_dest_ptr; #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ /* * Initialize destination --- called by jpeg_start_compress * before any data is actually written. */ void init_destination (j_compress_ptr cinfo) { stream_dest_ptr dest = (stream_dest_ptr) cinfo->dest; /* Allocate the output buffer --- it will be released when done with image */ dest->buffer = (JOCTET *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof(JOCTET)); dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; } /* * Empty the output buffer --- called whenever buffer fills up. * * In typical applications, this should write the entire output buffer * (ignoring the current state of next_output_byte & free_in_buffer), * reset the pointer & count to the start of the buffer, and return TRUE * indicating that the buffer has been dumped. * * In applications that need to be able to suspend compression due to output * overrun, a FALSE return indicates that the buffer cannot be emptied now. * In this situation, the compressor will return to its caller (possibly with * an indication that it has not accepted all the supplied scanlines). The * application should resume compression after it has made more room in the * output buffer. Note that there are substantial restrictions on the use of * suspension --- see the documentation. * * When suspending, the compressor will back up to a convenient restart point * (typically the start of the current MCU). next_output_byte & free_in_buffer * indicate where the restart point will be if the current call returns FALSE. * Data beyond this point will be regenerated after resumption, so do not * write it out when emptying the buffer externally. */ boolean empty_output_buffer (j_compress_ptr cinfo) { stream_dest_ptr dest = (stream_dest_ptr) cinfo->dest; dest->outfile->write((const char*)dest->buffer,OUTPUT_BUF_SIZE); if (dest->outfile->bad()) ERREXIT(cinfo, JERR_FILE_WRITE); dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; return TRUE; } /* * Terminate destination --- called by jpeg_finish_compress * after all data has been written. Usually needs to flush buffer. * * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding * application must deal with any cleanup that should happen even * for error exit. */ void term_destination (j_compress_ptr cinfo) { stream_dest_ptr dest = (stream_dest_ptr) cinfo->dest; size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; /* Write any data remaining in the buffer */ if (datacount > 0) { dest->outfile->write((const char*)dest->buffer,datacount); if (dest->outfile->bad()) ERREXIT(cinfo, JERR_FILE_WRITE); } dest->outfile->flush(); /* Make sure we wrote the output file OK */ if (dest->outfile->bad()) ERREXIT(cinfo, JERR_FILE_WRITE); } /* * Prepare for output to a stdio stream. * The caller must have already opened the stream, and is responsible * for closing it after finishing compression. */ void jpeg_stream_dest (j_compress_ptr cinfo, std::ostream * outfile) { stream_dest_ptr dest; /* The destination object is made permanent so that multiple JPEG images * can be written to the same file without re-executing jpeg_stdio_dest. * This makes it dangerous to use this manager and a different destination * manager serially with the same JPEG object, because their private object * sizes may be different. Caveat programmer. */ if (cinfo->dest == NULL) { /* first time for this JPEG object? */ cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(stream_destination_mgr)); } dest = (stream_dest_ptr) cinfo->dest; dest->pub.init_destination = init_destination; dest->pub.empty_output_buffer = empty_output_buffer; dest->pub.term_destination = term_destination; dest->outfile = outfile; } /* END OF READ/WRITE STREAM CODE */ int simage_jpeg_error(char * buffer, int buflen) { switch (jpegerror) { case ERR_OPEN: strncpy(buffer, "JPEG loader: Error opening file", buflen); break; case ERR_MEM: strncpy(buffer, "JPEG loader: Out of memory error", buflen); break; case ERR_JPEGLIB: strncpy(buffer, "JPEG loader: Illegal jpeg file", buflen); break; } return jpegerror; } struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr * my_error_ptr; static void my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ /*(*cinfo->err->output_message) (cinfo);*/ /* FIXME: get error messahe from jpeglib */ /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } static void my_output_message (j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (*cinfo->err->format_message) (cinfo, buffer); OSG_WARN<alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); width = cinfo.output_width; height = cinfo.output_height; buffer = currPtr = new unsigned char [width*height*cinfo.output_components]; /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ /* flip image upside down */ if (buffer) { currPtr = buffer + row_stride * (cinfo.output_height-1); while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ (void) jpeg_read_scanlines(&cinfo, rowbuffer, 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ currPtr = copyScanline(currPtr, rowbuffer[0], row_stride); } } /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ //fclose(infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ if (buffer) { *width_ret = width; *height_ret = height; *numComponents_ret = format; } else { jpegerror = ERR_MEM; } return buffer; } } // namespace osgDBJPEG class ReaderWriterJPEG : public osgDB::ReaderWriter { WriteResult::WriteStatus write_JPEG_file (std::ostream &fout, const osg::Image &img, int quality = 100) const { if (!img.isDataContiguous()) { OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG plugin."<getOptionString()); std::string opt; while (iss >> opt) { if(opt=="JPEG_QUALITY") { int quality; iss >> quality; return quality; } } } return 100; } public: ReaderWriterJPEG() { supportsExtension("jpeg","JPEG image format"); supportsExtension("jpg","JPEG image format"); } virtual const char* className() const { return "JPEG Image Reader/Writer"; } ReadResult readJPGStream(std::istream& fin) const { unsigned char *imageData = NULL; int width_ret; int height_ret; int numComponents_ret; unsigned int exif_orientation=0; imageData = osgDBJPEG::simage_jpeg_load(fin, &width_ret, &height_ret, &numComponents_ret, &exif_orientation); if (imageData==NULL) return ReadResult::ERROR_IN_READING_FILE; int s = width_ret; int t = height_ret; int r = 1; //int internalFormat = numComponents_ret; int internalFormat = numComponents_ret == 1 ? GL_LUMINANCE : numComponents_ret == 2 ? GL_LUMINANCE_ALPHA : numComponents_ret == 3 ? GL_RGB : numComponents_ret == 4 ? GL_RGBA : (GLenum)-1; unsigned int pixelFormat = numComponents_ret == 1 ? GL_LUMINANCE : numComponents_ret == 2 ? GL_LUMINANCE_ALPHA : numComponents_ret == 3 ? GL_RGB : numComponents_ret == 4 ? GL_RGBA : (GLenum)-1; unsigned int dataType = GL_UNSIGNED_BYTE; osg::ref_ptr pOsgImage = new osg::Image; pOsgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); if (exif_orientation>0) { // guide for meaning of exif_orientation provided by webpage: http://sylvana.net/jpegcrop/exif_orientation.html switch(exif_orientation) { case(1): OSG_INFO<<"EXIF_Orientation 1 (top, left side), No need to rotate image. "<s()-1, 0, 0), osg::Vec3i(-pOsgImage->s(), 0, 0), osg::Vec3i(0, pOsgImage->t(), 0), osg::Vec3i(0, 0, 1)); break; case(3): OSG_INFO<<"EXIF_Orientation 3 (bottom, right side), rotate 180."<s()-1, pOsgImage->t()-1, 0), osg::Vec3i(-pOsgImage->s(), 0, 0), osg::Vec3i(0, -pOsgImage->t(), 0), osg::Vec3i(0, 0, 1)); break; case(4): OSG_INFO<<"EXIF_Orientation 4 (bottom, left side). flip y, rotate 180."<t()-1, 0), osg::Vec3i(pOsgImage->s(), 0, 0), osg::Vec3i(0, -pOsgImage->t(), 0), osg::Vec3i(0, 0, 1)); break; case(5): OSG_INFO<<"EXIF_Orientation 5 (left side, top). flip y, rotate 90."<s()-1, pOsgImage->t()-1, 0), osg::Vec3i(0, -pOsgImage->t(), 0), osg::Vec3i(-pOsgImage->s(), 0, 0), osg::Vec3i(0, 0, 1)); break; case(6): OSG_INFO<<"EXIF_Orientation 6 (right side, top). rotate 90."<s()-1, 0, 0), osg::Vec3i(0, pOsgImage->t(), 0), osg::Vec3i(-pOsgImage->s(), 0, 0), osg::Vec3i(0, 0, 1)); break; case(7): OSG_INFO<<"EXIF_Orientation 7 (right side, bottom), flip Y, rotate 270."<t(), 0), osg::Vec3i(pOsgImage->s(), 0, 0), osg::Vec3i(0, 0, 1)); case(8): OSG_INFO<<"EXIF_Orientation 8 (left side, bottom). rotate 270."<t()-1, 0), osg::Vec3i(0, -pOsgImage->t(), 0), osg::Vec3i(pOsgImage->s(), 0, 0), osg::Vec3i(0, 0, 1)); break; } } return pOsgImage.release(); } virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(fin, options); } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(file, options); } virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const { return readJPGStream(fin); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::ERROR_IN_READING_FILE; ReadResult rr = readJPGStream(istream); if(rr.validImage()) rr.getImage()->setFileName(file); return rr; } virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options *options) const { osg::ref_ptr tmp_img = new osg::Image(img); tmp_img->flipVertical(); WriteResult::WriteStatus ws = write_JPEG_file(fout, *(tmp_img.get()), getQuality(options)); return ws; } virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; return writeImage(img,fout,options); } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(jpeg, ReaderWriterJPEG) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/jpeg/CMakeLists.txt0000644000175000017500000000030413151044751025465 0ustar albertoalbertoINCLUDE_DIRECTORIES( ${JPEG_INCLUDE_DIR} ) SET(TARGET_SRC EXIF_Orientation.cpp ReaderWriterJPEG.cpp ) SET(TARGET_LIBRARIES_VARS JPEG_LIBRARY ) #### end var setup ### SETUP_PLUGIN(jpeg) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/jpeg/EXIF_Orientation.cpp0000644000175000017500000001342713151044751026551 0ustar albertoalberto#include "EXIF_Orientation.h" #include #include #include #include #define EXIF_IDENT_STRING "Exif\000\000" static unsigned short de_get16(void *ptr, bool byteSwap) { unsigned short val; memcpy(&val, ptr, sizeof(val)); if (byteSwap) osg::swapBytes(val); return val; } static unsigned int de_get32(void *ptr, bool byteSwap) { unsigned int val; memcpy(&val, ptr, sizeof(val)); if (byteSwap) osg::swapBytes(val); return val; } int EXIF_Orientation (j_decompress_ptr cinfo) { OSG_INFO<<"get_orientation()"<marker_list; while (cmarker) { if (cmarker->marker == EXIF_JPEG_MARKER) { /* The Exif APP1 marker should contain a unique identification string ("Exif\0\0"). Check for it. */ if (!memcmp (cmarker->data, EXIF_IDENT_STRING, 6)) { exif_marker = cmarker; } } cmarker = cmarker->next; } if (exif_marker==NULL) { OSG_INFO<<"exif_marker not found "<data_length < 32) { OSG_INFO<<"exif_marker too short : "<data_length<data points to the first data after the APP1 marker and length entries, which is the exif identification string. The TIFF header should thus normally be found at i=6, below, and the pointer to IFD0 will be at 6+4 = 10. */ /* Check for TIFF header and catch endianness */ unsigned int i = 0; for(i=0; i < 16; ++i) { /* Little endian TIFF header */ if (memcmp (&exif_marker->data[i], leth, 4) == 0) { tiffHeaderEndian = osg::LittleEndian; break; } /* Big endian TIFF header */ else if (memcmp (&exif_marker->data[i], beth, 4) == 0) { tiffHeaderEndian = osg::BigEndian; break; } } /* So did we find a TIFF header or did we just hit end of buffer? */ if (i >= 16) { OSG_INFO<<"Could not find TIFF header"<data[i], swapBytes); unsigned int type = de_get16(&exif_marker->data[i + 2], swapBytes); unsigned int count = de_get32(&exif_marker->data[i + 4], swapBytes); OSG_INFO<<" tag=0x"< extern "C" { #include #include "jerror.h" } #define EXIF_JPEG_MARKER JPEG_APP0+1 extern int EXIF_Orientation (j_decompress_ptr cinfo); #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/md2/0000755000175000017500000000000013151044751022465 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/md2/anorms.h0000644000175000017500000001473213151044751024144 0ustar albertoalberto /* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ {-0.525731f, 0.000000f, 0.850651f}, {-0.442863f, 0.238856f, 0.864188f}, {-0.295242f, 0.000000f, 0.955423f}, {-0.309017f, 0.500000f, 0.809017f}, {-0.162460f, 0.262866f, 0.951056f}, {0.000000f, 0.000000f, 1.000000f}, {0.000000f, 0.850651f, 0.525731f}, {-0.147621f, 0.716567f, 0.681718f}, {0.147621f, 0.716567f, 0.681718f}, {0.000000f, 0.525731f, 0.850651f}, {0.309017f, 0.500000f, 0.809017f}, {0.525731f, 0.000000f, 0.850651f}, {0.295242f, 0.000000f, 0.955423f}, {0.442863f, 0.238856f, 0.864188f}, {0.162460f, 0.262866f, 0.951056f}, {-0.681718f, 0.147621f, 0.716567f}, {-0.809017f, 0.309017f, 0.500000f}, {-0.587785f, 0.425325f, 0.688191f}, {-0.850651f, 0.525731f, 0.000000f}, {-0.864188f, 0.442863f, 0.238856f}, {-0.716567f, 0.681718f, 0.147621f}, {-0.688191f, 0.587785f, 0.425325f}, {-0.500000f, 0.809017f, 0.309017f}, {-0.238856f, 0.864188f, 0.442863f}, {-0.425325f, 0.688191f, 0.587785f}, {-0.716567f, 0.681718f, -0.147621f}, {-0.500000f, 0.809017f, -0.309017f}, {-0.525731f, 0.850651f, 0.000000f}, {0.000000f, 0.850651f, -0.525731f}, {-0.238856f, 0.864188f, -0.442863f}, {0.000000f, 0.955423f, -0.295242f}, {-0.262866f, 0.951056f, -0.162460f}, {0.000000f, 1.000000f, 0.000000f}, {0.000000f, 0.955423f, 0.295242f}, {-0.262866f, 0.951056f, 0.162460f}, {0.238856f, 0.864188f, 0.442863f}, {0.262866f, 0.951056f, 0.162460f}, {0.500000f, 0.809017f, 0.309017f}, {0.238856f, 0.864188f, -0.442863f}, {0.262866f, 0.951056f, -0.162460f}, {0.500000f, 0.809017f, -0.309017f}, {0.850651f, 0.525731f, 0.000000f}, {0.716567f, 0.681718f, 0.147621f}, {0.716567f, 0.681718f, -0.147621f}, {0.525731f, 0.850651f, 0.000000f}, {0.425325f, 0.688191f, 0.587785f}, {0.864188f, 0.442863f, 0.238856f}, {0.688191f, 0.587785f, 0.425325f}, {0.809017f, 0.309017f, 0.500000f}, {0.681718f, 0.147621f, 0.716567f}, {0.587785f, 0.425325f, 0.688191f}, {0.955423f, 0.295242f, 0.000000f}, {1.000000f, 0.000000f, 0.000000f}, {0.951056f, 0.162460f, 0.262866f}, {0.850651f, -0.525731f, 0.000000f}, {0.955423f, -0.295242f, 0.000000f}, {0.864188f, -0.442863f, 0.238856f}, {0.951056f, -0.162460f, 0.262866f}, {0.809017f, -0.309017f, 0.500000f}, {0.681718f, -0.147621f, 0.716567f}, {0.850651f, 0.000000f, 0.525731f}, {0.864188f, 0.442863f, -0.238856f}, {0.809017f, 0.309017f, -0.500000f}, {0.951056f, 0.162460f, -0.262866f}, {0.525731f, 0.000000f, -0.850651f}, {0.681718f, 0.147621f, -0.716567f}, {0.681718f, -0.147621f, -0.716567f}, {0.850651f, 0.000000f, -0.525731f}, {0.809017f, -0.309017f, -0.500000f}, {0.864188f, -0.442863f, -0.238856f}, {0.951056f, -0.162460f, -0.262866f}, {0.147621f, 0.716567f, -0.681718f}, {0.309017f, 0.500000f, -0.809017f}, {0.425325f, 0.688191f, -0.587785f}, {0.442863f, 0.238856f, -0.864188f}, {0.587785f, 0.425325f, -0.688191f}, {0.688191f, 0.587785f, -0.425325f}, {-0.147621f, 0.716567f, -0.681718f}, {-0.309017f, 0.500000f, -0.809017f}, {0.000000f, 0.525731f, -0.850651f}, {-0.525731f, 0.000000f, -0.850651f}, {-0.442863f, 0.238856f, -0.864188f}, {-0.295242f, 0.000000f, -0.955423f}, {-0.162460f, 0.262866f, -0.951056f}, {0.000000f, 0.000000f, -1.000000f}, {0.295242f, 0.000000f, -0.955423f}, {0.162460f, 0.262866f, -0.951056f}, {-0.442863f, -0.238856f, -0.864188f}, {-0.309017f, -0.500000f, -0.809017f}, {-0.162460f, -0.262866f, -0.951056f}, {0.000000f, -0.850651f, -0.525731f}, {-0.147621f, -0.716567f, -0.681718f}, {0.147621f, -0.716567f, -0.681718f}, {0.000000f, -0.525731f, -0.850651f}, {0.309017f, -0.500000f, -0.809017f}, {0.442863f, -0.238856f, -0.864188f}, {0.162460f, -0.262866f, -0.951056f}, {0.238856f, -0.864188f, -0.442863f}, {0.500000f, -0.809017f, -0.309017f}, {0.425325f, -0.688191f, -0.587785f}, {0.716567f, -0.681718f, -0.147621f}, {0.688191f, -0.587785f, -0.425325f}, {0.587785f, -0.425325f, -0.688191f}, {0.000000f, -0.955423f, -0.295242f}, {0.000000f, -1.000000f, 0.000000f}, {0.262866f, -0.951056f, -0.162460f}, {0.000000f, -0.850651f, 0.525731f}, {0.000000f, -0.955423f, 0.295242f}, {0.238856f, -0.864188f, 0.442863f}, {0.262866f, -0.951056f, 0.162460f}, {0.500000f, -0.809017f, 0.309017f}, {0.716567f, -0.681718f, 0.147621f}, {0.525731f, -0.850651f, 0.000000f}, {-0.238856f, -0.864188f, -0.442863f}, {-0.500000f, -0.809017f, -0.309017f}, {-0.262866f, -0.951056f, -0.162460f}, {-0.850651f, -0.525731f, 0.000000f}, {-0.716567f, -0.681718f, -0.147621f}, {-0.716567f, -0.681718f, 0.147621f}, {-0.525731f, -0.850651f, 0.000000f}, {-0.500000f, -0.809017f, 0.309017f}, {-0.238856f, -0.864188f, 0.442863f}, {-0.262866f, -0.951056f, 0.162460f}, {-0.864188f, -0.442863f, 0.238856f}, {-0.809017f, -0.309017f, 0.500000f}, {-0.688191f, -0.587785f, 0.425325f}, {-0.681718f, -0.147621f, 0.716567f}, {-0.442863f, -0.238856f, 0.864188f}, {-0.587785f, -0.425325f, 0.688191f}, {-0.309017f, -0.500000f, 0.809017f}, {-0.147621f, -0.716567f, 0.681718f}, {-0.425325f, -0.688191f, 0.587785f}, {-0.162460f, -0.262866f, 0.951056f}, {0.442863f, -0.238856f, 0.864188f}, {0.162460f, -0.262866f, 0.951056f}, {0.309017f, -0.500000f, 0.809017f}, {0.147621f, -0.716567f, 0.681718f}, {0.000000f, -0.525731f, 0.850651f}, {0.425325f, -0.688191f, 0.587785f}, {0.587785f, -0.425325f, 0.688191f}, {0.688191f, -0.587785f, 0.425325f}, {-0.955423f, 0.295242f, 0.000000f}, {-0.951056f, 0.162460f, 0.262866f}, {-1.000000f, 0.000000f, 0.000000f}, {-0.850651f, 0.000000f, 0.525731f}, {-0.955423f, -0.295242f, 0.000000f}, {-0.951056f, -0.162460f, 0.262866f}, {-0.864188f, 0.442863f, -0.238856f}, {-0.951056f, 0.162460f, -0.262866f}, {-0.809017f, 0.309017f, -0.500000f}, {-0.864188f, -0.442863f, -0.238856f}, {-0.951056f, -0.162460f, -0.262866f}, {-0.809017f, -0.309017f, -0.500000f}, {-0.681718f, 0.147621f, -0.716567f}, {-0.681718f, -0.147621f, -0.716567f}, {-0.850651f, 0.000000f, -0.525731f}, {-0.688191f, 0.587785f, -0.425325f}, {-0.587785f, 0.425325f, -0.688191f}, {-0.425325f, 0.688191f, -0.587785f}, {-0.425325f, -0.688191f, -0.587785f}, {-0.587785f, -0.425325f, -0.688191f}, {-0.688191f, -0.587785f, -0.425325f}, OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/md2/CMakeLists.txt0000644000175000017500000000014713151044751025227 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterMD2.cpp ) SET(TARGET_H anorms.h ) #### end var setup ### SETUP_PLUGIN(md2) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/md2/ReaderWriterMD2.cpp0000644000175000017500000003303213151044751026074 0ustar albertoalberto/* * ReaderWriterMD2.cpp * * MD2 Reading code * * Author(s): Vladimir Vukicevic * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(WIN32) && !defined(__CYGWIN__) # include #else # include #endif #include #include static osg::Node* load_md2 (const char *filename, const osgDB::ReaderWriter::Options* options); class ReaderWriterMD2 : public osgDB::ReaderWriter { public: ReaderWriterMD2 () { supportsExtension("md2","Quak2 MD format"); } virtual const char* className () const { return "Quake MD2 Reader"; } virtual ReadResult readNode (const std::string& filename, const osgDB::ReaderWriter::Options* options) const; }; REGISTER_OSGPLUGIN(md2, ReaderWriterMD2) osgDB::ReaderWriter::ReadResult ReaderWriterMD2::readNode (const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; // code for setting up the database path so that internally referenced file are searched for on relative paths. osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; local_opt->setDatabasePath(osgDB::getFilePath(fileName)); return load_md2 (fileName.c_str(), options); } /////////////////// MD2 parsing code ////////////////////// typedef struct { int magic; int version; int skinWidth; int skinHeight; int frameSize; // size of each frame in bytes int numSkins; int numVertices; // number of vertices in each frame int numTexcoords; // number of texcoords in each frame (usually same as numVertices) int numTriangles; // number of triangles in each frame int numGlCommands; int numFrames; // number of frames int offsetSkins; int offsetTexCoords; int offsetTriangles; int offsetFrames; int offsetGlCommands; // num dwords in gl commands list int offsetEnd; } MD2_HEADER; #define MD2_HEADER_MAGIC 0x32504449 typedef struct { unsigned char vertex[3]; unsigned char lightNormalIndex; } MD2_VERTEX; typedef struct { float scale[3]; float translate[3]; char name[16]; MD2_VERTEX vertices[1]; } MD2_FRAME; typedef struct { short vertexIndices[3]; short textureIndices[3]; } MD2_TRIANGLE; typedef struct { float s; float t; int vertexIndex; } MD2_GLCOMMANDVERTEX; typedef struct { short s; short t; } MD2_TEXTURECOORDINATE; typedef struct { char name[64]; } MD2_SKIN; #define NUMVERTEXNORMALS 162 float g_md2VertexNormals[NUMVERTEXNORMALS][3] = { #include "anorms.h" }; osg::Vec3Array *g_md2NormalsArray = NULL; // // the result will be an osg::Switch // whose children will be osg::Sequences, one for each animation // the children of the osg::Sequence will be the osg::Geode that contains the // osg::Geometry of the relevant frame. The osg::Geode will have a osg::StateSet // containing the texture information. // // this is also quite non-portable to non-little-endian architectures static osg::Node* load_md2 (const char *filename, const osgDB::ReaderWriter::Options* options) { struct stat st; void *mapbase; int file_fd; osg::Node* result = NULL; if (stat (filename, &st) < 0) { return NULL; } file_fd = open (filename, O_RDONLY); if (file_fd <= 0) { close (file_fd); return NULL; } mapbase = malloc (st.st_size); if (!mapbase) { close (file_fd); return NULL; } if (read(file_fd, mapbase, st.st_size)==0) { close (file_fd); if (mapbase) free(mapbase); return NULL; } if (g_md2NormalsArray == NULL) { g_md2NormalsArray = new osg::Vec3Array; for (int i = 0; i < NUMVERTEXNORMALS; i++) g_md2NormalsArray->push_back (osg::Vec3 (g_md2VertexNormals[i][0], g_md2VertexNormals[i][1], g_md2VertexNormals[i][2])); } MD2_HEADER *md2_header = (MD2_HEADER *) mapbase; if (md2_header->magic != MD2_HEADER_MAGIC || md2_header->version != 8) { #if 0 munmap (mapbase); #else free (mapbase); #endif close (file_fd); return NULL; } MD2_SKIN *md2_skins = (MD2_SKIN *) ((unsigned char *) mapbase + md2_header->offsetSkins); MD2_TEXTURECOORDINATE *md2_texcoords = (MD2_TEXTURECOORDINATE *) ((unsigned char *) mapbase + md2_header->offsetTexCoords); MD2_TRIANGLE *md2_triangles = (MD2_TRIANGLE *) ((unsigned char *) mapbase + md2_header->offsetTriangles); osg::Switch *base_switch = new osg::Switch (); osg::Sequence *current_sequence = NULL; // read in the frame info into a vector const char *last_frame_name = NULL; osg::ref_ptr vertexCoords = NULL; osg::ref_ptr texCoords = NULL; osg::ref_ptr vertexIndices = NULL; osg::ref_ptr texIndices = NULL; osg::ref_ptr normalCoords = NULL; osg::ref_ptr normalIndices = NULL; // load the texture skins // there is code here to support multiple skins, but there's no need for it // since we really just want to support one; we have no way of returning more // than one to the user in any case. #if 0 std::vector skin_textures; for (int si = 0; si < md2_header->numSkins; si++) { osg::ref_ptr img; osg::ref_ptr tex; std::string imgname (md2_skins[si].name); // first try loading the imgname straight img = osgDB::readRefImageFile (imgname, options); if (img.valid()) { tex = new osg::Texture2D; tex->setImage (img); skin_textures.push_back (tex); continue; } // we failed, so check if it's a PCX image if (imgname.size() > 4 && osgDB::equalCaseInsensitive (imgname.substr (imgname.size() - 3, 3), "pcx")) { // it's a pcx, so try bmp and tga, since pcx sucks std::string basename = imgname.substr (0, imgname.size() - 3); img = osgDB::readRefImageFile (basename + "bmp", options); if (img.valid()) { tex = new osg::Texture2D; tex->setImage (img.get()); skin_textures.push_back (tex); continue; } img = osgDB::readRefImageFile (basename + "tga", options); if (img.valid()) { tex = new osg::Texture2D; tex->setImage (img,get()); skin_textures.push_back (tex); continue; } } // couldn't find the referenced texture skin for this model skin_textures.push_back (NULL); OSG_WARN << "MD2 Loader: Couldn't load skin " << imgname << " referenced by model " << filename << std::endl; } #else // load the single skin osg::ref_ptr skin_image; osg::ref_ptr skin_texture = NULL; if (md2_header->numSkins > 0) { std::string imgname (md2_skins[0].name); do { // first try loading the imgname straight skin_image = osgDB::readRefImageFile(imgname, options); if (skin_image.valid()) break; // we failed, so check if it's a PCX image if (imgname.size() > 4 && osgDB::equalCaseInsensitive (imgname.substr (imgname.size() - 3, 3), "pcx")) { // it's a pcx, so try bmp and tga, since pcx sucks std::string basename = imgname.substr (0, imgname.size() - 3); skin_image = osgDB::readRefImageFile (basename + "bmp", options); if (skin_image.valid()) break; skin_image = osgDB::readRefImageFile (basename + "tga", options); if (skin_image.valid()) break; } } while (0); if (skin_image.valid()) { skin_texture = new osg::Texture2D; skin_texture->setImage (skin_image.get()); skin_texture->setFilter (osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST); } else { // couldn't find the referenced texture skin for this model OSG_WARN << "MD2 Loader: Couldn't load skin " << imgname << " referenced by model " << filename << std::endl; } } #endif int sequence_frame = 0; for (int curFrame = 0; curFrame < md2_header->numFrames; curFrame++) { // std::cerr << "Num vertices " << md2_header->numVertices << std::endl; //long *command = (long *) ((unsigned char *) mapbase + md2_header->offsetGlCommands); MD2_FRAME *frame = (MD2_FRAME *) ((unsigned char *) mapbase + md2_header->offsetFrames + (md2_header->frameSize * curFrame)); MD2_VERTEX *frame_vertices = frame->vertices; // std::cerr << "Reading frame " << curFrame << " (gl offset: " << md2_header->offsetGlCommands << ") name: " << frame->name << std::endl; int last_len = last_frame_name ? strcspn (last_frame_name, "0123456789") : 0; int cur_len = strcspn (frame->name, "0123456789"); if (last_len != cur_len || strncmp (last_frame_name, frame->name, last_len) != 0) { if (current_sequence) { current_sequence->setInterval (osg::Sequence::LOOP, 0, -1); base_switch->addChild (current_sequence); } current_sequence = new osg::Sequence (); current_sequence->setMode (osg::Sequence::START); current_sequence->setDuration (1.0f, -1); sequence_frame = 0; current_sequence->setName (std::string (frame->name, cur_len)); } vertexCoords = new osg::Vec3Array; normalCoords = new osg::Vec3Array; for (int vi = 0; vi < md2_header->numVertices; vi++) { vertexCoords->push_back (osg::Vec3 (frame_vertices[vi].vertex[0] * frame->scale[0] + frame->translate[0], -1 * (frame_vertices[vi].vertex[2] * frame->scale[2] + frame->translate[2]), frame_vertices[vi].vertex[1] * frame->scale[1] + frame->translate[1])); osg::Vec3 z = (*g_md2NormalsArray) [frame_vertices[vi].lightNormalIndex]; normalCoords->push_back (z); } if (curFrame == 0) { vertexIndices = new osg::UIntArray; normalIndices = new osg::UIntArray; texCoords = new osg::Vec2Array; texIndices = new osg::UIntArray; for (int vi = 0; vi < md2_header->numTexcoords; vi++) { texCoords->push_back (osg::Vec2 ((float) md2_texcoords[vi].s / md2_header->skinWidth, 1.0f - (float) md2_texcoords[vi].t / md2_header->skinHeight)); } for (int ti = 0; ti < md2_header->numTriangles; ti++) { vertexIndices->push_back (md2_triangles[ti].vertexIndices[0]); vertexIndices->push_back (md2_triangles[ti].vertexIndices[1]); vertexIndices->push_back (md2_triangles[ti].vertexIndices[2]); normalIndices->push_back (md2_triangles[ti].vertexIndices[0]); normalIndices->push_back (md2_triangles[ti].vertexIndices[1]); normalIndices->push_back (md2_triangles[ti].vertexIndices[2]); texIndices->push_back (md2_triangles[ti].textureIndices[0]); texIndices->push_back (md2_triangles[ti].textureIndices[1]); texIndices->push_back (md2_triangles[ti].textureIndices[2]); } } osg::ref_ptr geom = new deprecated_osg::Geometry; geom->setVertexArray (vertexCoords.get()); geom->setVertexIndices (vertexIndices.get()); geom->setTexCoordArray (0, texCoords.get()); geom->setTexCoordIndices (0, texIndices.get()); geom->setNormalArray (normalCoords.get()); geom->setNormalIndices (normalIndices.get()); geom->setNormalBinding (deprecated_osg::Geometry::BIND_PER_VERTEX); geom->addPrimitiveSet (new osg::DrawArrays (osg::PrimitiveSet::TRIANGLES, 0, vertexIndices->size ())); osg::ref_ptr geode = new osg::Geode; geode->addDrawable (geom.get()); current_sequence->addChild (geode.get()); current_sequence->setTime (sequence_frame, 0.2f); sequence_frame++; last_frame_name = frame->name; } if (current_sequence) { current_sequence->setInterval (osg::Sequence::LOOP, 0, -1); base_switch->addChild (current_sequence); } osg::StateSet *state = new osg::StateSet; if (skin_texture != NULL) { state->setTextureAttributeAndModes (0, skin_texture.get(), osg::StateAttribute::ON); } base_switch->setStateSet (state); //base_switch->setAllChildrenOff (); base_switch->setSingleChildOn(0); result = base_switch; #if 0 munamp (mapbase); #else free (mapbase); #endif close (file_fd); return result; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/shadow/0000755000175000017500000000000013151044751023270 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/shadow/CMakeLists.txt0000644000175000017500000000021013151044751026021 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterOsgShadow.cpp ) SET(TARGET_ADDED_LIBRARIES osgShadow ) #### end var setup ### SETUP_PLUGIN(osgshadow) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/shadow/ReaderWriterOsgShadow.cpp0000644000175000017500000001206513151044751030216 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2007 Robert Osfield * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #include #include #include #include #include #include #include #include #include #define EXTENSION_NAME "osgShadow" static bool getFilenameAndParams(const std::string& input, std::string& filename, std::string& params) { // find the start of the params list, accounting for nesting of [] and () brackets, // note, we are working backwards. int noNestedBrackets = 0; std::string::size_type pos = input.size(); for(; pos>0; ) { --pos; char c = input[pos]; if (c==']') ++noNestedBrackets; else if (c=='[') --noNestedBrackets; else if (c==')') ++noNestedBrackets; else if (c=='(') --noNestedBrackets; else if (c=='.' && noNestedBrackets==0) break; } // get the next "extension", which actually contains the pseudo-loader parameters params = input.substr(pos+1, std::string::npos ); if( params.empty() ) { OSG_WARN << "Missing parameters for " EXTENSION_NAME " pseudo-loader" << std::endl; return false; } // clear the params sting of any brackets. std::string::size_type params_pos = params.size(); for(; params_pos>0; ) { --params_pos; char c = params[params_pos]; if (c==']' || c=='[' || c==')' || c=='(') { params.erase(params_pos,1); } } // strip the "params extension", which must leave a sub-filename. filename = input.substr(0, pos ); return true; } /////////////////////////////////////////////////////////////////////////// class ReaderWriterOsgShadow : public osgDB::ReaderWriter { public: ReaderWriterOsgShadow() { supportsExtension("osgShadow","OpenSceneGraph osgShadow extension to .osg ascii format"); supportsExtension("shadow","OpenSceneGraph osgShadow extension pseudo loader"); } virtual const char* className() const { return "osgShadow pseudo-loader"; } virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(fileName); if( !acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED; // strip the pseudo-loader extension std::string tmpName = osgDB::getNameLessExtension( fileName ); if (tmpName.empty()) return ReadResult::FILE_NOT_HANDLED; std::string subFileName, params; if (!getFilenameAndParams(tmpName, subFileName, params)) { return ReadResult::FILE_NOT_HANDLED; } if( subFileName.empty()) { OSG_WARN << "Missing subfilename for " EXTENSION_NAME " pseudo-loader" << std::endl; return ReadResult::FILE_NOT_HANDLED; } OSG_INFO << " params = \"" << params << "\"" << std::endl; OSG_INFO << " subFileName = \"" << subFileName << "\"" << std::endl; osg::ref_ptr technique; if (!params.empty()) { if (params=="ShadowVolume" || params=="sv") technique = new osgShadow::ShadowVolume; else if (params=="ShadowTexture" || params=="st") technique = new osgShadow::ShadowTexture; else if (params=="ShadowMap" || params=="sm") technique = new osgShadow::ShadowMap; // else if (params=="ParallelSplitShadowMap" || params=="pssm") technique = new osgShadow::ParallelSplitShadowMap; else subFileName += std::string(".") + params; } // default fallback to using ShadowVolume if (!technique) technique = new osgShadow::ShadowVolume; // recursively load the subfile. osg::ref_ptr node = osgDB::readRefNodeFile( subFileName, options ); if( !node ) { // propagate the read failure upwards OSG_WARN << "Subfile \"" << subFileName << "\" could not be loaded" << std::endl; return ReadResult::FILE_NOT_HANDLED; } osgShadow::ShadowedScene* shadowedScene = new osgShadow::ShadowedScene; shadowedScene->setShadowTechnique(technique); shadowedScene->addChild( node ); return shadowedScene; } }; // Add ourself to the Registry to instantiate the reader/writer. REGISTER_OSGPLUGIN(osgShadow, ReaderWriterOsgShadow) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/vnc/0000755000175000017500000000000013151044751022571 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/vnc/ReaderWriterVNC.cpp0000644000175000017500000003133113151044751026244 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1999-2008 Robert Osfield * * This software is open source and may be redistributed and/or modified under * the terms of the GNU General Public License (GPL) version 2.0. * The full license is in LICENSE.txt file included with this distribution,. * * This software 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 * include LICENSE.txt for more details. */ #include #include #include #include #include extern "C" { #include } class LibVncImage : public osgWidget::VncImage { public: LibVncImage(); bool connect(const std::string& hostname); void close(); virtual bool sendPointerEvent(int x, int y, int buttonMask); double getTimeOfLastRender() const { return _timeOfLastRender; } double time() const { return osg::Timer::instance()->time_s(); } virtual bool sendKeyEvent(int key, bool keyDown); virtual void setFrameLastRendered(const osg::FrameStamp* frameStamp); static rfbBool resizeImage(rfbClient* client); static void updateImage(rfbClient* client,int x,int y,int w,int h); static void passwordCheck(rfbClient* client,const char* encryptedPassWord,int len); static char* getPassword(rfbClient* client); std::string _optionString; std::string _username; std::string _password; double _timeOfLastRender; osg::ref_ptr _inactiveBlock; protected: virtual ~LibVncImage(); class RfbThread : public osg::Referenced, public OpenThreads::Thread { public: RfbThread(rfbClient* client, LibVncImage* image): _client(client), _image(image), _done(false) {} virtual ~RfbThread() { _done = true; if (isRunning()) { cancel(); join(); } } virtual void run() { do { // OSG_NOTICE<<"RfThread::run()"<updated(); } else { // OSG_NOTICE<<"Timed out"<time(); double timeBeforeIdle = 0.1; if (currentTime > _image->getTimeOfLastRender()+timeBeforeIdle) { //OSG_NOTICE<<"New: Time to idle"<_inactiveBlock->reset(); _image->_inactiveBlock->block(); //OSG_NOTICE<<" Finished block."< _image; bool _done; }; public: rfbClient* _client; osg::ref_ptr _rfbThread; }; LibVncImage::LibVncImage(): _client(0) { // setPixelBufferObject(new osg::PixelBufferObject(this); _inactiveBlock = new osg::RefBlock; } LibVncImage::~LibVncImage() { close(); } static rfbBool rfbInitConnection(rfbClient* client) { /* Unless we accepted an incoming connection, make a TCP connection to the given VNC server */ if (!client->listenSpecified) { if (!client->serverHost || !ConnectToRFBServer(client,client->serverHost,client->serverPort)) return FALSE; } /* Initialise the VNC connection, including reading the password */ if (!InitialiseRFBConnection(client)) return FALSE; if (!SetFormatAndEncodings(client)) return FALSE; client->width=client->si.framebufferWidth; client->height=client->si.framebufferHeight; client->MallocFrameBuffer(client); if (client->updateRect.x < 0) { client->updateRect.x = client->updateRect.y = 0; client->updateRect.w = client->width; client->updateRect.h = client->height; } if (client->appData.scaleSetting>1) { if (!SendScaleSetting(client, client->appData.scaleSetting)) return FALSE; if (!SendFramebufferUpdateRequest(client, client->updateRect.x / client->appData.scaleSetting, client->updateRect.y / client->appData.scaleSetting, client->updateRect.w / client->appData.scaleSetting, client->updateRect.h / client->appData.scaleSetting, FALSE)) return FALSE; } else { if (!SendFramebufferUpdateRequest(client, client->updateRect.x, client->updateRect.y, client->updateRect.w, client->updateRect.h, FALSE)) return FALSE; } return TRUE; } void LibVncImage::passwordCheck(rfbClient* client,const char* encryptedPassWord,int len) { OSG_NOTICE<<"LibVncImage::passwordCheck"<_password<_password.c_str()); } bool LibVncImage::connect(const std::string& hostname) { if (hostname.empty()) return false; if (_client) close(); _client = rfbGetClient(8,3,4); _client->canHandleNewFBSize = TRUE; _client->MallocFrameBuffer = resizeImage; _client->GotFrameBufferUpdate = updateImage; _client->HandleKeyboardLedState = 0; _client->HandleTextChat = 0; // provide the password if we have one assigned if (!_password.empty()) _client->GetPassword = getPassword; rfbClientSetClientData(_client, 0, this); size_t pos = hostname.find(":"); if (pos == std::string::npos) { _client->serverHost = strdup(hostname.c_str()); } else { _client->serverHost = strdup(hostname.substr(0, pos).c_str()); _client->serverPort = atoi(hostname.substr(pos+1).c_str()); } // _client->appData.qualityLevel = ; // _client->appData.encodings = ; // _client->appData.compressLevel = ; // _client->appData.scaleSetting = ; if(rfbInitConnection(_client)) { _rfbThread = new RfbThread(_client, this); _rfbThread->startThread(); return true; } else { close(); return false; } } void LibVncImage::close() { if (_rfbThread.valid()) { _inactiveBlock->release(); // stop the client thread _rfbThread = 0; } if (_client) { // close the client rfbClientCleanup(_client); _client = 0; } } rfbBool LibVncImage::resizeImage(rfbClient* client) { LibVncImage* image = (LibVncImage*)(rfbClientGetClientData(client, 0)); int width = client->width; int height = client->height; int depth = client->format.bitsPerPixel; OSG_NOTICE<<"resize "<_optionString.find("swop")!=std::string::npos) swap = true; } GLenum gl_pixelFormat = swap ? GL_BGRA : GL_RGBA; if (!image->_optionString.empty()) { if (image->_optionString.find("RGB")!=std::string::npos) gl_pixelFormat = GL_RGBA; if (image->_optionString.find("RGBA")!=std::string::npos) gl_pixelFormat = GL_RGBA; if (image->_optionString.find("BGR")!=std::string::npos) gl_pixelFormat = GL_BGRA; if (image->_optionString.find("BGRA")!=std::string::npos) gl_pixelFormat = GL_BGRA; } image->allocateImage(width, height, 1, gl_pixelFormat, GL_UNSIGNED_BYTE); image->setInternalTextureFormat(GL_RGBA); client->frameBuffer= (uint8_t*)(image->data()); return TRUE; } void LibVncImage::updateImage(rfbClient* client,int x,int y,int w,int h) { LibVncImage* image = (LibVncImage*)(rfbClientGetClientData(client, 0)); image->dirty(); } bool LibVncImage::sendPointerEvent(int x, int y, int buttonMask) { if (_client) { SendPointerEvent(_client ,x, y, buttonMask); return true; } return false; } bool LibVncImage::sendKeyEvent(int key, bool keyDown) { if (_client) { SendKeyEvent(_client, key, keyDown ? TRUE : FALSE); return true; } return false; } void LibVncImage::setFrameLastRendered(const osg::FrameStamp*) { _timeOfLastRender = time(); // release block _inactiveBlock->release(); } class ReaderWriterVNC : public osgDB::ReaderWriter { public: ReaderWriterVNC() { supportsExtension("vnc","VNC plugin"); supportsOption("swap","Swaps the pixel format order, exchanging the red and blue channels."); supportsOption("swop","American spelling, same effect as swap."); supportsOption("RGB","Use RGBA pixel format for the vnc image"); supportsOption("RGBA","Use RGBA pixel format for the vnc image"); supportsOption("BGR","Use BGRA pixel format for the vnc image"); supportsOption("BGRA","Use BGRA pixel format for the vnc image"); } virtual const char* className() const { return "VNC plugin"; } virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const { return readImage(file,options); } virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { if (!osgDB::equalCaseInsensitive(osgDB::getFileExtension(fileName),"vnc")) { return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; } std::string hostname = osgDB::getNameLessExtension(fileName); OSG_NOTICE<<"Hostname = "< image = new LibVncImage; image->setDataVariance(osg::Object::DYNAMIC); image->setOrigin(osg::Image::TOP_LEFT); const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ? options->getAuthenticationMap() : osgDB::Registry::instance()->getAuthenticationMap(); const osgDB::AuthenticationDetails* details = authenticationMap ? authenticationMap->getAuthenticationDetails(hostname) : 0; // configure authentication if required. if (details) { OSG_NOTICE<<"Passing in password = "<password<_username = details->username; image->_password = details->password; } if (options && !options->getOptionString().empty()) { image->_optionString = options->getOptionString(); } if (!image->connect(hostname)) { return "Could not connect to "+hostname; } return image.get(); } virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult result = readImage(fileName, options); if (!result.validImage()) return result; osg::ref_ptr vncClient = new osgWidget::VncClient(); if (vncClient->assign(dynamic_cast(result.getImage()))) { return vncClient.release(); } else { return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; } } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(vnc, ReaderWriterVNC) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/vnc/CMakeLists.txt0000644000175000017500000000042313151044751025330 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterVNC.cpp ) INCLUDE_DIRECTORIES(${LIBVNCSERVER_INCLUDE_DIR}) SET(TARGET_EXTERNAL_LIBRARIES ${LIBVNCCLIENT_LIBRARY} ${ZLIB_LIBRARY} ${JPEG_LIBRARY} ) SET(TARGET_ADDED_LIBRARIES osgWidget ) #### end var setup ### SETUP_PLUGIN(vnc vnc) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gz/0000755000175000017500000000000013151044751022423 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gz/CMakeLists.txt0000644000175000017500000000025213151044751025162 0ustar albertoalbertoINCLUDE_DIRECTORIES( ${ZLIB_INCLUDE_DIR} ) SET(TARGET_SRC ReaderWriterGZ.cpp ) SET(TARGET_LIBRARIES_VARS ZLIB_LIBRARY ) #### end var setup ### SETUP_PLUGIN(gz) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gz/ReaderWriterGZ.cpp0000644000175000017500000003003213151044751025765 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////////////////////// // // ReaderWriterGZ // class ReaderWriterGZ : public osgDB::ReaderWriter { public: enum ObjectType { OBJECT, ARCHIVE, IMAGE, HEIGHTFIELD, NODE }; ReaderWriterGZ(); ~ReaderWriterGZ(); virtual const char* className() const { return "HTTP Protocol Model Reader"; } virtual ReadResult openArchive(const std::string& fileName,ArchiveStatus status, unsigned int , const Options* options) const { if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED); else return readFile(ARCHIVE,fileName,options); } virtual ReadResult readObject(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return readFile(OBJECT,fileName,options); } virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return readFile(IMAGE,fileName,options); } virtual ReadResult readHeightField(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return readFile(HEIGHTFIELD,fileName,options); } virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return readFile(NODE,fileName,options); } ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options* options) const; ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const; virtual WriteResult writeObject(const osg::Object& obj, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return writeFile(OBJECT, &obj, fileName, options); } virtual WriteResult writeImage(const osg::Image& image, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return writeFile(IMAGE, &image, fileName, options); } virtual WriteResult writeHeightField(const osg::HeightField& hf, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return writeFile(HEIGHTFIELD, &hf, fileName, options); } virtual WriteResult writeNode(const osg::Node& node, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { return writeFile(NODE, &node, fileName,options); } WriteResult writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fin, const osgDB::ReaderWriter::Options* options) const; WriteResult writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const; bool read(std::istream& fin, std::string& destination) const; bool write(std::ostream& fout, const std::string& source) const; }; ReaderWriterGZ::ReaderWriterGZ() { // OSG_NOTICE<<"ReaderWriterGZ::ReaderWriterGZ()"<readObject(fin,options); case(ARCHIVE): return rw->openArchive(fin,options); case(IMAGE): return rw->readImage(fin,options); case(HEIGHTFIELD): return rw->readHeightField(fin,options); case(NODE): return rw->readNode(fin,options); default: break; } return ReadResult::FILE_NOT_HANDLED; } osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const { std::string ext = osgDB::getLowerCaseFileExtension(fullFileName); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; if (osgDB::containsServerAddress(fullFileName)) return ReadResult::FILE_NOT_HANDLED; osgDB::ReaderWriter* rw = 0; if (osgDB::equalCaseInsensitive(ext,"osgz")) { rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg"); OSG_INFO<<"osgz ReaderWriter "<getReaderWriterForExtension("ive"); OSG_INFO<<"ivez ReaderWriter "<getReaderWriterForExtension(baseExt); OSG_INFO< local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); osgDB::ifstream fin(fileName.c_str(), std::ios::binary|std::ios::in); if (!fin) return ReadResult::ERROR_IN_READING_FILE; std::string dest; read(fin, dest); std::stringstream strstream(dest); return readFile(objectType, rw, strstream, local_opt.get()); } osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fout, const osgDB::ReaderWriter::Options *options) const { switch(objectType) { case(OBJECT): return rw->writeObject(*object, fout, options); case(IMAGE): return rw->writeImage(*(dynamic_cast(object)), fout, options); case(HEIGHTFIELD): return rw->writeHeightField(*(dynamic_cast(object)), fout, options); case(NODE): return rw->writeNode(*(dynamic_cast(object)), fout,options); default: break; } return WriteResult::FILE_NOT_HANDLED; } osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const { std::string ext = osgDB::getLowerCaseFileExtension(fullFileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; osgDB::ReaderWriter* rw = 0; if (osgDB::equalCaseInsensitive(ext,"osgz")) { rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg"); OSG_NOTICE<<"osgz ReaderWriter "<getReaderWriterForExtension("ive"); OSG_NOTICE<<"ivez ReaderWriter "<getReaderWriterForExtension(baseExt); OSG_NOTICE<0) fout.write((const char*)out, have); if (fout.fail()) { (void)deflateEnd(&strm); return false; } } while (strm.avail_out == 0); /* clean up and return */ (void)deflateEnd(&strm); return true; } // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(GZ, ReaderWriterGZ) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/0000755000175000017500000000000013151044751024042 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/TexturePaletteManager.h0000644000175000017500000000261213151044751030466 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_TEXTURE_PALETTE_MANAGER_H__ #define __FLTEXP_TEXTURE_PALETTE_MANAGER_H__ 1 #include "ExportOptions.h" #include #include namespace osg { class Texture2D; } namespace flt { class DataOutputStream; class FltExportVisitor; class TexturePaletteManager { public: TexturePaletteManager( const FltExportVisitor& nv, const ExportOptions& fltOpt ); int add( int unit, const osg::Texture2D* texture ); void write( DataOutputStream& dos ) const; protected: TexturePaletteManager& operator = (const TexturePaletteManager&) { return *this; } int _currIndex; typedef std::map< const osg::Texture2D*, int > TextureIndexMap; TextureIndexMap _indexMap; const FltExportVisitor& _nv; const ExportOptions& _fltOpt; }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/LightSourcePaletteManager.h0000644000175000017500000000335713151044751031265 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_LIGHT_SOURCE_PALETTE_MANAGER_H__ #define __FLTEXP_LIGHT_SOURCE_PALETTE_MANAGER_H__ 1 #include "ExportOptions.h" #include namespace osg { class Light; } namespace flt { class DataOutputStream; class LightSourcePaletteManager { public: LightSourcePaletteManager(); // Add a light to the palette and auto-assign it the next available index int add(osg::Light const* light); // Write the light palette records out to a DataOutputStream void write( DataOutputStream& dos ) const; private: int _currIndex; // Helper struct to hold light palette records struct LightRecord { LightRecord(osg::Light const* light, int i) : Light(light) , Index(i) { } osg::Light const* Light; int Index; }; // Map to allow lookups by Light pointer typedef std::map LightPalette; LightPalette _lightPalette; protected: LightSourcePaletteManager& operator = (const LightSourcePaletteManager&) { return *this; } }; } // End namespace fltexp #endif // !__FLTEXP_LIGHT_SOURCE_PALETTE_MANAGER_H__ OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Record.h0000644000175000017500000001014513151044751025432 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_RECORD_H #define FLT_RECORD_H 1 #include #include #include #include #include #include #include #include "Vertex.h" namespace flt { class RecordInputStream; class Document; class PrimaryRecord; class Matrix; #define META_Record(name) \ virtual flt::Record* cloneType() const { return new name (); } \ virtual bool isSameKindAs(const flt::Record* rec) const { return dynamic_cast(rec)!=NULL; } #define META_setID(imp) virtual void setID(const std::string& id) { if (imp.valid()) imp->setName(id); } #define META_setComment(imp) virtual void setComment(const std::string& id) { if (imp.valid()) imp->addDescription(id); } #define META_setMultitexture(imp) virtual void setMultitexture(osg::StateSet& multitexture) { if (imp.valid()) imp->getOrCreateStateSet()->merge(multitexture); } #define META_addChild(imp) virtual void addChild(osg::Node& child) { if (imp.valid()) imp->addChild(&child); } #define META_dispose(imp) virtual void dispose(Document&) { if (imp.valid() && _matrix.valid()) insertMatrixTransform(*imp,*_matrix,_numberOfReplications); } // pure virtual base class class Record : public osg::Referenced { public: Record(); virtual Record* cloneType() const = 0; virtual bool isSameKindAs(const Record* rec) const = 0; virtual void read(RecordInputStream& in, Document& document); void setParent(PrimaryRecord* parent); protected: virtual ~Record(); virtual void readRecord(RecordInputStream& in, Document& document); osg::ref_ptr _parent; }; class PrimaryRecord : public Record { public: PrimaryRecord(); virtual void read(RecordInputStream& in, Document& document); virtual void dispose(Document& /*document*/) {} // Ancillary operations virtual void setID(const std::string& /*id*/) {} virtual void setComment(const std::string& /*comment*/) {} virtual void setMultitexture(osg::StateSet& /*multitexture*/) {} virtual void addChild(osg::Node& /*child*/) {} virtual void addVertex(Vertex& /*vertex*/) {} virtual void addVertexUV(int /*layer*/,const osg::Vec2& /*uv*/) {} virtual void addMorphVertex(Vertex& /*vertex0*/, Vertex& /*vertex100*/) {} virtual void setMultiSwitchValueName(unsigned int /*switchSet*/, const std::string& /*name*/) {} void setNumberOfReplications(int num) { _numberOfReplications = num; } void setMatrix(const osg::Matrix& matrix) { _matrix = new osg::RefMatrix(matrix); } void setLocalVertexPool(VertexList* pool) { _localVertexPool = pool; } VertexList* getLocalVertexPool() { return _localVertexPool.get(); } protected: virtual ~PrimaryRecord() {} int _numberOfReplications; osg::ref_ptr _matrix; osg::ref_ptr _localVertexPool; }; /** DummyRecord - */ class DummyRecord : public Record { public: DummyRecord() {} META_Record(DummyRecord) protected: virtual ~DummyRecord() {} }; void insertMatrixTransform(osg::Node& node, const osg::Matrix& matrix, int numberOfReplications); osg::Vec3Array* getOrCreateVertexArray(osg::Geometry& geometry); osg::Vec3Array* getOrCreateNormalArray(osg::Geometry& geometry); osg::Vec4Array* getOrCreateColorArray(osg::Geometry& geometry); osg::Vec2Array* getOrCreateTextureArray(osg::Geometry& geometry, int unit); } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/TexturePaletteManager.cpp0000644000175000017500000000477713151044751031037 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "TexturePaletteManager.h" #include "FltExportVisitor.h" #include "ExportOptions.h" #include "DataOutputStream.h" #include "Opcodes.h" #include #include #include #include namespace flt { TexturePaletteManager::TexturePaletteManager( const FltExportVisitor& nv, const ExportOptions& fltOpt ) : _currIndex( 0 ), _nv( nv ), _fltOpt( fltOpt ) { } int TexturePaletteManager::add( int unit, const osg::Texture2D* texture ) { if( (!texture) || (!texture->getImage()) ) return -1; int index( -1 ); TextureIndexMap::const_iterator it = _indexMap.find( texture ); if (it != _indexMap.end()) index = it->second; else { index = _currIndex++; _indexMap[ texture ] = index; // If there is no .attr file, write one _nv.writeATTRFile( unit, texture ); } return index; } void TexturePaletteManager::write( DataOutputStream& dos ) const { int x( 0 ), y( 0 ), height( 0 ); TextureIndexMap::const_iterator it = _indexMap.begin(); while (it != _indexMap.end()) { const osg::Texture2D* texture = it->first; int index = it->second; std::string fileName; if ( _fltOpt.getStripTextureFilePath() ) fileName = osgDB::getSimpleFileName( texture->getImage()->getFileName() ); else fileName = texture->getImage()->getFileName(); dos.writeInt16( (int16) TEXTURE_PALETTE_OP ); dos.writeUInt16( 216 ); dos.writeString( fileName, 200 ); dos.writeInt32( index ); dos.writeInt32( x ); dos.writeInt32( y ); it++; x += texture->getImage()->s(); if (texture->getImage()->t() > height) height = texture->getImage()->t(); if (x > 1024) { x = 0; y += height; height = 0; } } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/DataInputStream.h0000644000175000017500000000340713151044751027264 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_DATAINPUTSTREAM #define FLT_DATAINPUTSTREAM 1 #include #include #include #include #include #include "Types.h" namespace flt { class Record; class DataInputStream : public std::istream { public: explicit DataInputStream(std::streambuf* sb); int8 readInt8(int8 def=0); uint8 readUInt8(uint8 def=0); int16 readInt16(int16 def=0); uint16 readUInt16(uint16 def=0); int32 readInt32(int32 def=0); uint32 readUInt32(uint32 def=0); float32 readFloat32(float32 def=0); float64 readFloat64(float64 def=0); void readCharArray(char* data, int size); std::string readString(int size); osg::Vec4f readColor32(); osg::Vec2f readVec2f(); osg::Vec3f readVec3f(); osg::Vec4f readVec4f(); osg::Vec3d readVec3d(); std::istream& forward(std::istream::off_type off); int16 peekInt16(); protected: bool _byteswap; }; } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/VertexRecords.cpp0000644000175000017500000002431613151044751027353 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include "Record.h" #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" namespace flt { // Color from ColorPool. osg::Vec4 getColorFromPool(int index, const ColorPool* colorPool) { osg::Vec4 color(1,1,1,1); if (colorPool) color = colorPool->getColor(index); return color; } // Vertex flags enum Flags { START_HARD_EDGE = (0x8000 >> 0), NORMAL_FROZEN = (0x8000 >> 1), NO_COLOR = (0x8000 >> 2), PACKED_COLOR = (0x8000 >> 3) }; class VertexC : public Record { public: VertexC() {} META_Record(VertexC) virtual ~VertexC() {} virtual void readRecord(RecordInputStream& in, Document& document) { /*int colorNameIndex =*/ in.readInt16(); uint16 flags = in.readUInt16(); osg::Vec3d coord = in.readVec3d(); osg::Vec4f packedColor = in.readColor32(); int colorIndex = in.readInt32(-1); Vertex vertex; vertex.setCoord(coord*document.unitScale()); // color if (flags & PACKED_COLOR) vertex.setColor(packedColor); // Packed color else if( ( (flags & NO_COLOR) == 0 ) && ( colorIndex >= 0 ) ) { // Only use the color index if the NO_COLOR bit is _not_ set // and the index isn't negative. vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(VertexC, VERTEX_C_OP) class VertexCN : public Record { public: VertexCN() {} META_Record(VertexCN) protected: virtual ~VertexCN() {} virtual void readRecord(RecordInputStream& in, Document& document) { /*int colorNameIndex =*/ in.readInt16(); uint16 flags = in.readUInt16(); osg::Vec3d coord = in.readVec3d(); osg::Vec3f normal = in.readVec3f(); osg::Vec4f packedColor = in.readColor32(); int colorIndex = in.readInt32(-1); Vertex vertex; vertex.setCoord(coord*document.unitScale()); vertex.setNormal(normal); // color if (flags & PACKED_COLOR) vertex.setColor(packedColor); // Packed color else if( ( (flags & NO_COLOR) == 0 ) && ( colorIndex >= 0 ) ) { // Only use the color index if the NO_COLOR bit is _not_ set // and the index isn't negative. vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(VertexCN, VERTEX_CN_OP) class VertexCT : public Record { public: VertexCT() {} META_Record(VertexCT) protected: virtual ~VertexCT() {} virtual void readRecord(RecordInputStream& in, Document& document) { /*int colorNameIndex =*/ in.readInt16(); uint16 flags = in.readUInt16(); osg::Vec3d coord = in.readVec3d(); osg::Vec2f uv = in.readVec2f(); osg::Vec4f packedColor = in.readColor32(); int colorIndex = in.readInt32(-1); Vertex vertex; vertex.setCoord(coord*document.unitScale()); vertex.setUV(0,uv); // color if (flags & PACKED_COLOR) vertex.setColor(packedColor); // Packed color else if( ( (flags & NO_COLOR) == 0 ) && ( colorIndex >= 0 ) ) { // Only use the color index if the NO_COLOR bit is _not_ set // and the index isn't negative. vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(VertexCT, VERTEX_CT_OP) class VertexCNT : public Record { public: VertexCNT() {} META_Record(VertexCNT) protected: virtual ~VertexCNT() {} virtual void readRecord(RecordInputStream& in, Document& document) { /*int colorNameIndex =*/ in.readInt16(); uint16 flags = in.readUInt16(); osg::Vec3d coord = in.readVec3d(); osg::Vec3f normal = in.readVec3f(); osg::Vec2f uv = in.readVec2f(); osg::Vec4f packedColor = in.readColor32(); int colorIndex = in.readInt32(-1); Vertex vertex; vertex.setCoord(coord*document.unitScale()); vertex.setNormal(normal); vertex.setUV(0,uv); if (!coord.valid()) { OSG_NOTICE<<"Warning: data error detected in VertexCNT::readRecord coord="<= 0 ) ) { // Only use the color index if the NO_COLOR bit is _not_ set // and the index isn't negative. vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(VertexCNT, VERTEX_CNT_OP) /** Absolute Vertex - * version < 13 */ class AbsoluteVertex : public Record { public: AbsoluteVertex() {} META_Record(AbsoluteVertex) protected: virtual ~AbsoluteVertex() {} virtual void readRecord(RecordInputStream& in, Document& document) { int32 x = in.readInt32(); int32 y = in.readInt32(); int32 z = in.readInt32(); Vertex vertex; // coord vertex.setCoord(osg::Vec3(x,y,z) * document.unitScale()); // optional texture coordinates if (in.getRecordBodySize() > (4+4+4)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(0,uv); } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(AbsoluteVertex, OLD_ABSOLUTE_VERTEX_OP) /** Shaded Vertex * version < 13 */ class ShadedVertex : public Record { public: ShadedVertex() {} META_Record(ShadedVertex) protected: virtual ~ShadedVertex() {} virtual void readRecord(RecordInputStream& in, Document& document) { int32 x = in.readInt32(); int32 y = in.readInt32(); int32 z = in.readInt32(); /*uint8 edgeFlag =*/ in.readUInt8(); /*uint8 shadingFlag =*/ in.readUInt8(); int colorIndex = (int)in.readInt16(); Vertex vertex; // coord vertex.setCoord(osg::Vec3(x,y,z) * document.unitScale()); // color if (colorIndex >= 0) vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool // optional texture coordinates if (in.getRecordBodySize() > (4+4+4+1+1+2)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(0,uv); } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(ShadedVertex, OLD_SHADED_VERTEX_OP) /** Normal Vertex * version < 13 */ class NormalVertex : public Record { public: NormalVertex() {} META_Record(NormalVertex) protected: virtual ~NormalVertex() {} virtual void readRecord(RecordInputStream& in, Document& document) { int32 x = in.readInt32(); int32 y = in.readInt32(); int32 z = in.readInt32(); /*uint8 edgeFlag =*/ in.readUInt8(); /*uint8 shadingFlag =*/ in.readUInt8(); int colorIndex = (int)in.readInt16(); osg::Vec3f normal = in.readVec3d(); Vertex vertex; vertex.setCoord(osg::Vec3(x,y,z) * document.unitScale()); vertex.setNormal(normal / (float)(1L<<30)); // color if (colorIndex >= 0) vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool // optional texture coordinates if (in.getRecordBodySize() > (4+4+4+1+1+2+3*8)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(0,uv); } if (_parent.valid()) _parent->addVertex(vertex); } }; REGISTER_FLTRECORD(NormalVertex, OLD_NORMAL_VERTEX_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/RoadRecords.cpp0000644000175000017500000000631313151044751026760 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" namespace flt { /** RoadSegment */ class RoadSegment : public PrimaryRecord { osg::ref_ptr _roadSegment; public: RoadSegment() {} META_Record(RoadSegment) META_setID(_roadSegment) META_setComment(_roadSegment) META_setMultitexture(_roadSegment) META_addChild(_roadSegment) META_dispose(_roadSegment) protected: virtual ~RoadSegment() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { _roadSegment = new osg::Group; std::string id = in.readString(8); _roadSegment->setName(id); // Add to parent. if (_parent.valid()) _parent->addChild(*_roadSegment); } }; REGISTER_FLTRECORD(RoadSegment, ROAD_SEGMENT_OP) /** RoadConstruction */ class RoadConstruction : public PrimaryRecord { osg::ref_ptr _roadConstruction; public: RoadConstruction() {} META_Record(RoadConstruction) META_setID(_roadConstruction) META_setComment(_roadConstruction) META_setMultitexture(_roadConstruction) META_addChild(_roadConstruction) META_dispose(_roadConstruction) protected: virtual ~RoadConstruction() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { _roadConstruction = new osg::Group; std::string id = in.readString(8); _roadConstruction->setName(id); // Add to parent. if (_parent.valid()) _parent->addChild(*_roadConstruction); } }; REGISTER_FLTRECORD(RoadConstruction, ROAD_CONSTRUCTION_OP) /** RoadPath */ class RoadPath : public PrimaryRecord { osg::ref_ptr _roadPath; public: RoadPath() {} META_Record(RoadPath) META_setID(_roadPath) META_setComment(_roadPath) META_setMultitexture(_roadPath) META_addChild(_roadPath) META_dispose(_roadPath) protected: virtual ~RoadPath() {} virtual void readRecord(RecordInputStream& /*in*/, Document& /*document*/) { _roadPath = new osg::Group; // Add to parent. if (_parent.valid()) _parent->addChild(*_roadPath); } }; REGISTER_FLTRECORD(RoadPath, ROAD_PATH_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Registry.h0000644000175000017500000001050613151044751026025 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_REGISTRY_H #define FLT_REGISTRY_H 1 #include #include #include #include "Opcodes.h" #include "Record.h" namespace flt { class Registry : public osg::Referenced { public: ~Registry(); static Registry* instance(); // Record prototypes void addPrototype(int opcode, Record* prototype); Record* getPrototype(int opcode); // External read queue typedef std::pair FilenameParentPair; // ExtNameNodePair; typedef std::queue ExternalQueue; inline ExternalQueue& getExternalReadQueue() { return _externalReadQueue; } void addToExternalReadQueue(const std::string& filename, osg::Group* parent); // Local cache void addExternalToLocalCache(const std::string& filename, osg::Node* node); osg::Node* getExternalFromLocalCache(const std::string& filename); void addTextureToLocalCache(const std::string& filename, osg::StateSet* stateset); osg::StateSet* getTextureFromLocalCache(const std::string& filename); void clearLocalCache(); protected: Registry(); typedef std::map > RecordProtoMap; RecordProtoMap _recordProtoMap; ExternalQueue _externalReadQueue; // External cache typedef std::map > ExternalCacheMap; ExternalCacheMap _externalCacheMap; // Texture cache typedef std::map > TextureCacheMap; TextureCacheMap _textureCacheMap; }; inline void Registry::addToExternalReadQueue(const std::string& filename, osg::Group* parent) { _externalReadQueue.push( FilenameParentPair(filename,parent) ); } inline void Registry::addExternalToLocalCache(const std::string& filename, osg::Node* node) { _externalCacheMap[filename] = node; } inline osg::Node* Registry::getExternalFromLocalCache(const std::string& filename) { ExternalCacheMap::iterator itr = _externalCacheMap.find(filename); if (itr != _externalCacheMap.end()) return (*itr).second.get(); return NULL; } inline void Registry::addTextureToLocalCache(const std::string& filename, osg::StateSet* stateset) { _textureCacheMap[filename] = stateset; } inline osg::StateSet* Registry::getTextureFromLocalCache(const std::string& filename) { TextureCacheMap::iterator itr = _textureCacheMap.find(filename); if (itr != _textureCacheMap.end()) return (*itr).second.get(); return NULL; } inline void Registry::clearLocalCache() { _externalCacheMap.clear(); _textureCacheMap.clear(); } /** Proxy class for automatic registration of reader/writers with the Registry.*/ template class RegisterRecordProxy { public: explicit RegisterRecordProxy(int opcode) { Registry::instance()->addPrototype(opcode,new T); } ~RegisterRecordProxy() {} }; ////////////////////////////////////////////////////////////////////////// extern "C" { typedef void (* CRecordFunction) (void); } struct RecordFunctionProxy { RecordFunctionProxy(CRecordFunction function) { (function)(); } }; #define USE_FLTRECORD(recname, opcode) \ extern "C" void osgfltrec_##recname_##opcode(void); \ static flt::RecordFunctionProxy proxy_fltrecord_##recname_##opcode(osgfltrec_##recname_##opcode); #define REGISTER_FLTRECORD(recname, opcode) \ extern "C" void osgfltrec_##recname_##opcode(void) {} \ static flt::RegisterRecordProxy g_proxy_fltrecord_##recname_##opcode(opcode); } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/expPrimaryRecords.cpp0000644000175000017500000006627413151044751030247 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "FltExportVisitor.h" #include "ExportOptions.h" #include "VertexPaletteManager.h" #include "LightSourcePaletteManager.h" #include "DataOutputStream.h" #include "Opcodes.h" #include #include #include #include #include #include #include #include #include #include #include // FIXME: This header was copied verbatim from the importer, with the only change // being that the symbols it defines are placed in namespace 'fltexp' instead // of 'flt'. Thus, this one-off copy has to be kept in sync with the // importer until the reader/writer are unified... #include "Pools.h" namespace flt { void FltExportVisitor::writeHeader( const std::string& headerName ) { int16 length; int32 version; const int ver = _fltOpt->getFlightFileVersionNumber(); if (ver == ExportOptions::VERSION_15_7) { length = 304; version = 1570; } else if (ver == ExportOptions::VERSION_15_8) { length = 324; version = 1580; } else // ExportOptions::VERSION_16_1: { length = 324; version = 1610; } int8 units; switch( _fltOpt->getFlightUnits() ) { case ExportOptions::KILOMETERS: units = 1; break; case ExportOptions::FEET: units = 4; break; case ExportOptions::INCHES: units = 5; break; case ExportOptions::NAUTICAL_MILES: units = 8; break; default: case ExportOptions::METERS: units = 0; break; } static const unsigned int SAVE_VERTEX_NORMALS_BIT = 0x80000000u >> 0; //static const unsigned int PACKED_COLOR_MODE_BIT = 0x80000000u >> 1; //static const unsigned int CAD_VIEW_MODE_BIT = 0x80000000u >> 2; uint32 flags( SAVE_VERTEX_NORMALS_BIT ); IdHelper id(*this, headerName); id.dos_ = &_dos; _dos.writeInt16( (int16) HEADER_OP ); _dos.writeInt16( length ); _dos.writeID( id ); _dos.writeInt32( version ); _dos.writeInt32( 0 ); // edit revision // TBD need platform-independent method to generate date/time string _dos.writeString( std::string(" "), 32 ); // date and time string for last rev _dos.writeInt16( 0 ); // next group id _dos.writeInt16( 0 ); // next LOD id _dos.writeInt16( 0 ); // next object id _dos.writeInt16( 0 ); // next face id _dos.writeInt16( 1 ); // unit multiplier _dos.writeInt8( units ); // coordinate units _dos.writeInt8( 0 ); // if TRUE, texwhite on new faces _dos.writeUInt32( flags ); // flags _dos.writeFill( sizeof( int32 ) * 6 ); // reserved _dos.writeInt32( 0 ); // projection _dos.writeFill( sizeof( int32 ) * 7 ); // reserved _dos.writeInt16( 0 ); // next DOF id _dos.writeInt16( 1 ); // vertex storage type, should always be 1 _dos.writeInt32( 100 ); // DB origin, 100=OpenFlight _dos.writeFloat64( 0. ); // SW corner X _dos.writeFloat64( 0. ); // SW corner Y _dos.writeFloat64( 0. ); // delta X _dos.writeFloat64( 0. ); // delta Y _dos.writeInt16( 0 ); // next sound id _dos.writeInt16( 0 ); // next path id _dos.writeFill( sizeof( int32 ) * 2 ); // reserved _dos.writeInt16( 0 ); // next clip id _dos.writeInt16( 0 ); // next text id _dos.writeInt16( 0 ); // next BSP id _dos.writeInt16( 0 ); // next switch id _dos.writeInt32( 0 ); // reserved _dos.writeFloat64( 0. ); // SW corner lat _dos.writeFloat64( 0. ); // SW corner lon _dos.writeFloat64( 0. ); // NE corner lat _dos.writeFloat64( 0. ); // NE corner lon _dos.writeFloat64( 0. ); // origin lat _dos.writeFloat64( 0. ); // origin lon _dos.writeFloat64( 0. ); // lambert upper lat _dos.writeFloat64( 0. ); // lambert upper lon _dos.writeInt16( 0 ); // next light source id _dos.writeInt16( 0 ); // next light point id _dos.writeInt16( 0 ); // next road id _dos.writeInt16( 0 ); // next CAT id _dos.writeFill( sizeof( int16 ) * 4 ); // reserved _dos.writeInt32( 0 ); // ellipsoid model, 0=WGS84 _dos.writeInt16( 0 ); // next adaptive id _dos.writeInt16( 0 ); // next curve id _dos.writeInt16( 0 ); // utm zone _dos.writeFill( 6 ); // reserved _dos.writeFloat64( 0. ); // delta z _dos.writeFloat64( 0. ); // radius _dos.writeInt16( 0 ); // next mesh id _dos.writeInt16( 0 ); // next light system id if (version >= 1580) { _dos.writeInt32( 0 ); // reserved _dos.writeFloat64( 0. ); // earth major axis for user defined ellipsoid _dos.writeFloat64( 0. ); // earth minor axis for user defined ellipsoid } } // Group flags static const unsigned int FORWARD_ANIM = 0x80000000u >> 1; static const unsigned int SWING_ANIM = 0x80000000u >> 2; //static const unsigned int BOUND_BOX_FOLLOW = 0x80000000u >> 3; //static const unsigned int FREEZE_BOUND_BOX = 0x80000000u >> 4; //static const unsigned int DEFAULT_PARENT = 0x80000000u >> 5; //static const unsigned int BACKWARD_ANIM = 0x80000000u >> 6; // // Convenience routine for writing Group nodes that aren't animated // void FltExportVisitor::writeGroup( const osg::Group& group ) { int32 flags = 0, loopCount = 0; float32 loopDuration = 0.0f, lastFrameDuration = 0.0f; writeGroup(group, flags, loopCount, loopDuration, lastFrameDuration); } void FltExportVisitor::writeGroup( const osg::Group& group, int32 flags, int32 loopCount, float32 loopDuration, float32 lastFrameDuration) // <-- placeholder: ignored { int16 length( 44 ); IdHelper id(*this, group.getName() ); _records->writeInt16( (int16) GROUP_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt16( 0 ); // Relative priority _records->writeInt16( 0 ); // Reserved _records->writeUInt32( flags ); _records->writeInt16( 0 ); // Special effect ID1 _records->writeInt16( 0 ); // Special effect ID2 _records->writeInt16( 0 ); // Significance _records->writeInt8( 0 ); // Layer code _records->writeInt8( 0 ); // Reserved _records->writeInt32( 0 ); // Reserved _records->writeInt32( loopCount ); _records->writeFloat32( loopDuration ); _records->writeFloat32( lastFrameDuration ); } // // Since OpenFlight doesn't have 'Sequence' records---just Group records that // may, optionally, be animated---this routine sets the animation-related // parameters for a Group record and simply forwards to writeGroup() // void FltExportVisitor::writeSequence( const osg::Sequence& sequence ) { int32 flags = 0, loopCount = 0; float32 loopDuration = 0.0f, lastFrameDuration = 0.0f; osg::Sequence::LoopMode mode; int firstChildDisplayed, lastChildDisplayed; sequence.getInterval(mode, firstChildDisplayed, lastChildDisplayed); if (firstChildDisplayed == 0) { flags |= FORWARD_ANIM; } else { flags &= ~FORWARD_ANIM; } if (mode == osg::Sequence::SWING) { flags |= SWING_ANIM; } else { flags &= ~SWING_ANIM; } // Do we loop infinitely, or only a certain number of times? float speedUp; int numReps; sequence.getDuration(speedUp, numReps); if (numReps != -1) { loopCount = numReps; } else { loopCount = 0; // == loop continuously } // Sum individual frame durations to get the total loopDuration for (unsigned int i = 0; i < sequence.getNumChildren(); ++i) { loopDuration += sequence.getTime(i); } lastFrameDuration = sequence.getLastFrameTime(); writeGroup(sequence, flags, loopCount, loopDuration, lastFrameDuration); } void FltExportVisitor::writeObject( const osg::Group& group, osgSim::ObjectRecordData* ord ) { uint16 length( 28 ); IdHelper id(*this, group.getName() ); if (!ord) { std::string warning( "fltexp: writeObject has invalid ObjectRecordData." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } _records->writeInt16( (int16) OBJECT_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( ord->_flags ); _records->writeInt16( ord->_relativePriority ); _records->writeUInt16( ord->_transparency ); _records->writeUInt16( ord->_effectID1 ); _records->writeUInt16( ord->_effectID2 ); _records->writeUInt16( ord->_significance ); _records->writeUInt16( 0 ); // reserved } void FltExportVisitor::writeDegreeOfFreedom( const osgSim::DOFTransform* dof ) { const osg::Matrix& invPut = dof->getInversePutMatrix(); // Origin of DOF coord sys osg::Vec3d origin( invPut.getTrans() ); osg::Vec3 xAxis( invPut(0,0), invPut(0,1), invPut(0,2) ); osg::Vec3 yAxis( invPut(1,0), invPut(1,1), invPut(1,2) ); // Reference point along DOF coord sys's X axis osg::Vec3d pointOnXAxis = origin + xAxis; // Reference point in DOF coord sys's X-Y plane osg::Vec3d pointInXYPlane = origin + yAxis; // Translations osg::Vec3d minTranslate( dof->getMinTranslate() ); osg::Vec3d maxTranslate( dof->getMaxTranslate() ); osg::Vec3d currTranslate( dof->getCurrentTranslate() ); osg::Vec3d incrTranslate( dof->getIncrementTranslate() ); // Rotations osg::Vec3d minHPR( dof->getMinHPR() ); osg::Vec3d maxHPR( dof->getMaxHPR() ); osg::Vec3d currHPR( dof->getCurrentHPR() ); osg::Vec3d incrHPR( dof->getIncrementHPR() ); // Scaling osg::Vec3d minScale( dof->getMinScale() ); osg::Vec3d maxScale( dof->getMaxScale() ); osg::Vec3d currScale( dof->getCurrentScale() ); osg::Vec3d incrScale( dof->getIncrementScale() ); uint16 length( 384 ); IdHelper id(*this, dof->getName() ); _records->writeInt16( (int16) DOF_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // 'Reserved' (unused) _records->writeVec3d( origin ); _records->writeVec3d( pointOnXAxis ); _records->writeVec3d( pointInXYPlane ); // Translations _records->writeFloat64( minTranslate.z() ); _records->writeFloat64( maxTranslate.z() ); _records->writeFloat64( currTranslate.z() ); _records->writeFloat64( incrTranslate.z() ); _records->writeFloat64( minTranslate.y() ); _records->writeFloat64( maxTranslate.y() ); _records->writeFloat64( currTranslate.y() ); _records->writeFloat64( incrTranslate.y() ); _records->writeFloat64( minTranslate.x() ); _records->writeFloat64( maxTranslate.x() ); _records->writeFloat64( currTranslate.x() ); _records->writeFloat64( incrTranslate.x() ); // Rotations: 0 = Yaw, 1 = Pitch, 2 = Roll _records->writeFloat64( osg::RadiansToDegrees(minHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(maxHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(currHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(incrHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(minHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(maxHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(currHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(incrHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(minHPR[0]) ); _records->writeFloat64( osg::RadiansToDegrees(maxHPR[0]) ); _records->writeFloat64( osg::RadiansToDegrees(currHPR[0]) ); _records->writeFloat64( osg::RadiansToDegrees(incrHPR[0]) ); // Scaling _records->writeFloat64( minScale.z() ); _records->writeFloat64( maxScale.z() ); _records->writeFloat64( currScale.z() ); _records->writeFloat64( incrScale.z() ); _records->writeFloat64( minScale.y() ); _records->writeFloat64( maxScale.y() ); _records->writeFloat64( currScale.y() ); _records->writeFloat64( incrScale.y() ); _records->writeFloat64( minScale.x() ); _records->writeFloat64( maxScale.x() ); _records->writeFloat64( currScale.x() ); _records->writeFloat64( incrScale.y() ); _records->writeInt32( dof->getLimitationFlags() ); // Constraint flags _records->writeInt32( 0 ); // 'Reserved' (unused) } // Parent pool override flags static const unsigned long COLOR_PALETTE_OVERRIDE = 0x80000000u >> 0; static const unsigned long MATERIAL_PALETTE_OVERRIDE = 0x80000000u >> 1; static const unsigned long TEXTURE_PALETTE_OVERRIDE = 0x80000000u >> 2; //static const unsigned long LINE_STYLE_PALETTE_OVERRIDE = 0x80000000u >> 3; //static const unsigned long SOUND_PALETTE_OVERRIDE = 0x80000000u >> 4; static const unsigned long LIGHT_SOURCE_PALETTE_OVERRIDE = 0x80000000u >> 5; static const unsigned long LIGHT_POINT_PALETTE_OVERRIDE = 0x80000000u >> 6; static const unsigned long SHADER_PALETTE_OVERRIDE = 0x80000000u >> 7; void FltExportVisitor::writeExternalReference( const osg::ProxyNode& proxy ) { uint16 length( 216 ); // Set sane defaults for the override flags unsigned long flags = COLOR_PALETTE_OVERRIDE | MATERIAL_PALETTE_OVERRIDE | TEXTURE_PALETTE_OVERRIDE | LIGHT_POINT_PALETTE_OVERRIDE | SHADER_PALETTE_OVERRIDE ; // Selectively turn off overrides for resources we don't need const ParentPools* pp = dynamic_cast(proxy.getUserData() ); if (pp && pp->getColorPool() ) flags &= ~COLOR_PALETTE_OVERRIDE; if (pp && pp->getMaterialPool() ) flags &= ~MATERIAL_PALETTE_OVERRIDE; if (pp && pp->getTexturePool() ) flags &= ~TEXTURE_PALETTE_OVERRIDE; if (pp && pp->getLightSourcePool() ) flags &= ~LIGHT_SOURCE_PALETTE_OVERRIDE; if (pp && pp->getLPAppearancePool() ) flags &= ~LIGHT_POINT_PALETTE_OVERRIDE; if (pp && pp->getShaderPool() ) flags &= ~SHADER_PALETTE_OVERRIDE; _records->writeInt16( (int16) EXTERNAL_REFERENCE_OP ); _records->writeInt16( length ); _records->writeString(proxy.getFileName(0), 200); _records->writeInt32(0); // Reserved _records->writeInt32(flags); _records->writeInt16(0); // ViewAsBoundingBox flag _records->writeInt16(0); // Reserved } void FltExportVisitor::writeLevelOfDetail( const osg::LOD& lod, osg::Vec3d const& center, double switchInDist, double switchOutDist) { uint16 length( 80 ); IdHelper id(*this, lod.getName() ); _records->writeInt16( (int16) LOD_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // 'Reserved' field _records->writeFloat64( switchInDist ); _records->writeFloat64( switchOutDist ); // Switch-out distance _records->writeInt16( 0 ); // Special Effect ID1 _records->writeInt16( 0 ); // Special Effect ID2 _records->writeInt32( 0 ); // Flags _records->writeFloat64( center.x() ); _records->writeFloat64( center.y() ); _records->writeFloat64( center.z() ); _records->writeFloat64( 0 ); // Transition range _records->writeFloat64( 0 ); // Significant size } void FltExportVisitor::writeLightSource( const osg::LightSource& node ) { static const unsigned int ENABLED = 0x80000000u >> 0; static const unsigned int GLOBAL = 0x80000000u >> 1; osg::Light const* light = node.getLight(); int index = _lightSourcePalette->add(light); osg::Vec4d const& lightPos = light->getPosition(); osg::Vec3f const& lightDir = light->getDirection(); uint32 flags = 0; osg::StateSet const* ss = getCurrentStateSet(); if (ss->getMode(GL_LIGHT0 + light->getLightNum() ) & osg::StateAttribute::ON) { flags |= ENABLED; } // If this light is enabled for the node at the top of our StateSet stack, // assume it is 'global' for OpenFlight's purposes ss = _stateSetStack.front().get(); if (ss->getMode(GL_LIGHT0 + light->getLightNum() ) & osg::StateAttribute::ON) { flags |= GLOBAL; } uint16 length( 64 ); IdHelper id(*this, node.getName() ); _records->writeInt16( (int16) LIGHT_SOURCE_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // Reserved _records->writeInt32( index ); // Index into light source palette _records->writeInt32( 0 ); // Reserved _records->writeUInt32( flags ); // Flags _records->writeInt32( 0 ); // Reserved _records->writeVec3d( osg::Vec3d( lightPos.x() , lightPos.y() , lightPos.z() ) ); // TODO: Verify that indices 0 and 1 correspond to yaw and pitch _records->writeFloat32( lightDir[0] ); // Yaw _records->writeFloat32( lightDir[1] ); // Pitch } void FltExportVisitor::writeSwitch( const osgSim::MultiSwitch* ms ) { int32 currMask = ms->getActiveSwitchSet(); int32 numMasks = ms->getSwitchSetList().size(); int32 numWordsPerMask = ms->getNumChildren() / 32; if (ms->getNumChildren() % 32 != 0) ++numWordsPerMask; uint16 length( 28 + numMasks * numWordsPerMask * sizeof(int32) ); IdHelper id(*this, ms->getName() ); _records->writeInt16( (int16) SWITCH_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // <-- 'Reserved' (unused) _records->writeInt32( currMask ); _records->writeInt32( numMasks ); _records->writeInt32( numWordsPerMask ); // For each mask... for (int i = 0; i < numMasks; ++i) { // ... write out the set of 32-bit words comprising the mask uint32 maskWord = 0; const osgSim::MultiSwitch::ValueList& maskBits = ms->getValueList(i); for (size_t j = 0; j < maskBits.size(); ++j) { // If this bit is set, set the corresponding mask word if (maskBits[j]) maskWord |= 1 << (j % 32); // If we just set the 31st (last) bit of the current word, need // to write it out and reset prior to continuing the loop if ( (j + 1) % 32 == 0 ) { _records->writeUInt32(maskWord); maskWord = 0; } } // If the mask size wasn't a multiple of 32, need to write out // the final word containing the 'remainder' bits if (maskBits.size() % 32 != 0) { _records->writeUInt32(maskWord); } } } void FltExportVisitor::writeSwitch( const osg::Switch* sw ) { // An osg::Switch is just a special case of an osgSim::MultiSwitch // that only has a single mask int32 currMask = 0; int32 numMasks = 1; int32 numWordsPerMask = sw->getNumChildren() / 32; if (sw->getNumChildren() % 32 != 0) ++numWordsPerMask; uint16 length( 28 + numMasks * numWordsPerMask * sizeof(int32) ); IdHelper id(*this, sw->getName() ); _records->writeInt16( (int16) SWITCH_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // <-- 'Reserved' (unused) _records->writeInt32( currMask ); _records->writeInt32( numMasks ); _records->writeInt32( numWordsPerMask ); // Bust the mask up into as many 32-bit words as are necessary to hold it uint32 maskWord = 0; const osg::Switch::ValueList& maskBits = sw->getValueList(); for (size_t i = 0; i < maskBits.size(); ++i) { // If this bit is set, set the corresponding mask word if (maskBits[i]) maskWord |= 1 << (i % 32); // If we just set the 31st (last) bit of the current word, need // to write it out and reset prior to continuing the loop if ( (i + 1) % 32 == 0 ) { _records->writeUInt32(maskWord); maskWord = 0; } } // If the mask size wasn't a multiple of 32, need to write out // the final word containing the 'remainder' bits if (maskBits.size() % 32 != 0) { _records->writeUInt32(maskWord); } } void FltExportVisitor::writeLightPoint( const osgSim::LightPointNode* lpn ) { enum Directionality { OMNIDIRECTIONAL = 0, UNIDIRECTIONAL = 1, BIDIRECTIONAL = 2 }; enum DisplayMode { RASTER = 0, CALLIG = 1, EITHER = 2 }; enum Modes { ENABLE = 0, DISABLE = 1 }; enum Flags { NO_BACK_COLOR = 0x80000000u >> 1, CALLIGRAPHIC = 0x80000000u >> 3, REFLECTIVE = 0x80000000u >> 4, PERSPECTIVE = 0x80000000u >> 8, FLASHING = 0x80000000u >> 9, ROTATING = 0x80000000u >> 10, ROTATE_CC = 0x80000000u >> 11, VISIBLE_DAY = 0x80000000u >> 15, VISIBLE_DUSK = 0x80000000u >> 16, VISIBLE_NIGHT = 0x80000000u >> 17 }; int32 flags( NO_BACK_COLOR ); if (lpn->getNumLightPoints() == 0) return; // In OSG, each LightPoint within a LightPointNode can have different appearance // parameters, but in OpenFlight, a Light Point Record contains a list of homogeneous // vertices. To be correct, we'd have to look at all LightPoints in the LightPointNode // and spew out multiple FLT records for each group that shared common appearance // parameters. Instead, we cheat: We take the first LightPoint and use its appearance // parameters for all LightPoints in the LightPointNode. const osgSim::LightPoint& lp0 = lpn->getLightPoint( 0 ); // No really good mapping between OSG and FLT light point animations. float32 animPeriod( 0.f ); float32 animEnabled( 0.f ); float32 animPhaseDelay( 0.f ); if (lp0._blinkSequence != NULL) { flags |= FLASHING; animPeriod = 4.f; animEnabled = 2.f; animPhaseDelay = lp0._blinkSequence->getPhaseShift(); } // Note that true bidirectional light points are currently unsupported (they are unavailable // in OSG, so we never write them out to FLT as BIDIRECTIONAL. int32 directionality( OMNIDIRECTIONAL ); float32 horizLobe( 360.f ); float32 vertLobe( 360.f ); float32 lobeRoll( 0.f ); const osgSim::DirectionalSector* ds = dynamic_cast< osgSim::DirectionalSector* >( lp0._sector.get() ); if (ds) { directionality = UNIDIRECTIONAL; horizLobe = osg::RadiansToDegrees( ds->getHorizLobeAngle() ); vertLobe = osg::RadiansToDegrees( ds->getVertLobeAngle() ); lobeRoll = osg::RadiansToDegrees( ds->getLobeRollAngle() ); } { // Braces req'd to invoke idHelper destructor (and potentially // write LongID record) before Push Record. const uint16 length( 156 ); IdHelper id( *this, lpn->getName() ); _records->writeInt16( (int16) LIGHT_POINT_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt16( 0 ); // Surface material code _records->writeInt16( 0 ); // Feature ID _records->writeUInt32( ~0u ); // OpenFlight erronously say -1, so will assume ~0u is OK. Back color for bidirectional _records->writeInt32( EITHER ); // Display mode _records->writeFloat32( lp0._intensity ); // Intensity _records->writeFloat32( 0.f ); // Back intensity TBD _records->writeFloat32( 0.f ); // min defocus _records->writeFloat32( 0.f ); // max defocus _records->writeInt32( DISABLE ); // Fading mode _records->writeInt32( DISABLE ); // Fog punch mode _records->writeInt32( DISABLE ); // Directional mode _records->writeInt32( 0 ); // Range mode _records->writeFloat32( lpn->getMinPixelSize() ); // min pixel size _records->writeFloat32( lpn->getMaxPixelSize() ); // max pixel size _records->writeFloat32( lp0._radius * 2.f ); // Actual size _records->writeFloat32( 1.f ); // transparent falloff pixel size _records->writeFloat32( 1.f ); // Transparent falloff exponent _records->writeFloat32( 1.f ); // Transparent falloff scalar _records->writeFloat32( 0.f ); // Transparent falloff clamp _records->writeFloat32( 1.f ); // Fog scalar _records->writeFloat32( 0.f ); // Reserved _records->writeFloat32( 0.f ); // Size difference threshold _records->writeInt32( directionality ); // Directionality _records->writeFloat32( horizLobe ); // Horizontal lobe angle _records->writeFloat32( vertLobe ); // Vertical lobe angle _records->writeFloat32( lobeRoll ); // Lobe roll angle _records->writeFloat32( 0.f ); // Directional falloff exponent _records->writeFloat32( 0.f ); // Directional ambient intensity _records->writeFloat32( animPeriod ); // Animation period in seconds _records->writeFloat32( animPhaseDelay ); // Animation phase delay in seconds _records->writeFloat32( animEnabled ); // Animation enabled period in seconds _records->writeFloat32( 1.f ); // Significance _records->writeInt32( 0 ); // Calligraphic draw order _records->writeInt32( flags ); // Flags _records->writeVec3f( osg::Vec3f( 0.f, 0.f, 0.f ) ); // Axis of rotation } { osg::ref_ptr< osg::Vec3dArray > v = new osg::Vec3dArray( lpn->getNumLightPoints() ); osg::ref_ptr< osg::Vec4Array > c = new osg::Vec4Array( lpn->getNumLightPoints() ); osg::ref_ptr< osg::Vec3Array > n = new osg::Vec3Array( lpn->getNumLightPoints() ); osg::Vec3f normal( 0.f, 0.f, 1.f ); unsigned int idx; for( idx=0; idxgetNumLightPoints(); idx++) { const osgSim::LightPoint& lp = lpn->getLightPoint( idx ); (*v)[ idx ] = lp._position; (*c)[ idx ] = lp._color; const osgSim::DirectionalSector* ds = dynamic_cast< osgSim::DirectionalSector* >( lp._sector.get() ); if (ds) normal = ds->getDirection(); (*n)[ idx ] = normal; } _vertexPalette->add( (const osg::Array*)NULL, v.get(), c.get(), n.get(), NULL, true, true, false ); } writeMatrix( lpn->getUserData() ); writeComment( *lpn ); writePush(); writeVertexList( 0, lpn->getNumLightPoints() ); writePop(); } void FltExportVisitor::writeColorPalette() { // FLT exporter doesn't use a color palette but writes // a bogus one to satisfy loaders that require it. uint16 length( 4228 ); _dos.writeInt16( (int16) COLOR_PALETTE_OP ); _dos.writeInt16( length ); _dos.writeFill( 128 ); // Reserved int idx; for( idx=0; idx<1024; idx++) _dos.writeUInt32( 0xffffffff ); // Color n } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/expAncillaryRecords.cpp0000644000175000017500000000567613151044751030541 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "FltExportVisitor.h" #include "DataOutputStream.h" #include "Opcodes.h" #include #include namespace flt { /** If the DataOutputStream parameter is NULL, write to the _records member variable. Otherwise, write to the specified DataOutputStream. */ void FltExportVisitor::writeComment( const osg::Node& node, DataOutputStream* dos ) { if (dos==NULL) dos = _records; // Write all descriptions as Comment records. unsigned int nd = node.getNumDescriptions(); unsigned int idx=0; while( idx < nd ) { const std::string& com = node.getDescription( idx ); unsigned int iLen = com.length() + 5; if (iLen > 0xffff) { // short overrun std::string warning( "fltexp: writeComment: Descriptions too long, resorts in short overrun. Skipping." ); _fltOpt->getWriteResult().warn( warning ); OSG_WARN << warning << std::endl; continue; } uint16 length( (uint16)iLen ); dos->writeInt16( (int16) COMMENT_OP ); dos->writeInt16( length ); dos->writeString( com ); idx++; } } /** If the DataOutputStream parameter is NULL, write to the _records member variable. Otherwise, write to the specified DataOutputStream. */ void FltExportVisitor::writeLongID( const std::string& id, DataOutputStream* dos ) { if (dos==NULL) dos = _records; uint16 length( 2 + 2 + id.length() + 1 ); // +1 for terminating '\0' dos->writeInt16( (int16) LONG_ID_OP ); dos->writeUInt16( length ); dos->writeString( id ); } void FltExportVisitor::writeMatrix( const osg::Referenced* ref ) { const osg::RefMatrix* rm = dynamic_cast( ref ); if (!rm) return; uint16 length( 4 + (16 * sizeof(float32)) ); _records->writeInt16( (int16) MATRIX_OP ); _records->writeUInt16( length ); int idx, jdx; for (idx=0; idx<4; idx++) { for (jdx=0; jdx<4; jdx++) { _records->writeFloat32( (*rm)( idx, jdx ) ); } } } void FltExportVisitor::writeContinuationRecord( const unsigned short length ) { OSG_DEBUG << "fltexp: Continuation record length: " << length+4 << std::endl; _records->writeInt16( (int16) CONTINUATION_OP ); _records->writeUInt16( length+4 ); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/PrimaryRecords.cpp0000644000175000017500000010150013151044751027510 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" namespace flt { /** Header */ class Header : public PrimaryRecord { static const unsigned int SAVE_VERTEX_NORMALS_BIT = 0x80000000u >> 0; static const unsigned int PACKED_COLOR_MODE_BIT = 0x80000000u >> 1; static const unsigned int CAD_VIEW_MODE_BIT = 0x80000000u >> 2; osg::ref_ptr _header; public: Header() {} META_Record(Header) META_setID(_header) META_setComment(_header) META_setMultitexture(_header) META_addChild(_header) protected: virtual ~Header() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); OSG_DEBUG << "ID: " << id << std::endl; uint32 format = in.readUInt32(); OSG_DEBUG << "Format: " << format << std::endl; document._version = format; /*uint32 revision =*/ in.readUInt32(); std::string revisionTime = in.readString(32); OSG_INFO << "Last revision: " << revisionTime << std::endl; in.forward(4*2); // Flight v.11 & 12 use integer coordinates int16 multDivUnits = in.readInt16(); // Units multiplier/divisor uint8 units = in.readUInt8(); // 0=Meters 1=Kilometers 4=Feet 5=Inches 8=Nautical miles /*uint8 textureWhite =*/ in.readUInt8(); /*uint32 flags =*/ in.readUInt32(); in.forward( 4*6 ); /*int32 projectionType =*/ in.readInt32(); in.forward( 4*7 ); /*int16 nextDOF =*/ in.readInt16(); /*int16 vertStorage =*/ in.readInt16(); /*int32 dbOrigin =*/ in.readInt32(); /*float64 swX =*/ in.readFloat64(); /*float64 swY =*/ in.readFloat64(); /*float64 deltaX =*/ in.readFloat64(); /*float64 deltaY =*/ in.readFloat64(); in.forward( 2*2 ); /* some "next bead" IDs */ in.forward( 4*2 ); /* reserved */ in.forward( 4*2 ); /* more "next bead" IDs */ in.forward( 4 ); /* reserved */ /*float64 swLat =*/ in.readFloat64(); /*float64 swLong =*/ in.readFloat64(); /*float64 neLat =*/ in.readFloat64(); /*float64 neLong =*/ in.readFloat64(); float64 originLat = in.readFloat64(); float64 originLong = in.readFloat64(); if (document.getDoUnitsConversion()) document._unitScale = unitsToMeters((CoordUnits)units) / unitsToMeters(document.getDesiredUnits()); if (document._version < VERSION_13) { if (multDivUnits >= 0) document._unitScale *= (double)multDivUnits; else document._unitScale /= (double)(-multDivUnits); } _header = new osg::Group; _header->setName(id); // Store model origin in returned Node userData. osgSim::GeographicLocation* loc = new osgSim::GeographicLocation; loc->set( originLat, originLong ); _header->setUserData( loc ); OSG_INFO << "DB lat=" << originLat << " lon=" << originLong << std::endl; document.setHeaderNode(_header.get()); } virtual void dispose(Document& document) { if (_header.valid()) { // Preset sampler uniforms. ShaderPool* sp = document.getShaderPool(); if (sp && !sp->empty()) { _header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit0", 0) ); _header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit1", 1) ); _header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit2", 2) ); _header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit3", 3) ); } } } }; REGISTER_FLTRECORD(Header, HEADER_OP) /** Group */ class Group : public PrimaryRecord { static const unsigned int FORWARD_ANIM = 0x80000000u >> 1; static const unsigned int SWING_ANIM = 0x80000000u >> 2; static const unsigned int BOUND_BOX_FOLLOW = 0x80000000u >> 3; static const unsigned int FREEZE_BOUND_BOX = 0x80000000u >> 4; static const unsigned int DEFAULT_PARENT = 0x80000000u >> 5; static const unsigned int BACKWARD_ANIM = 0x80000000u >> 6; osg::ref_ptr _group; uint32 _flags; bool _forwardAnim; bool _backwardAnim; int32 _loopCount; float32 _loopDuration; float32 _lastFrameDuration; public: Group(): _flags(0), _forwardAnim(false), _backwardAnim(false), _loopCount(0), _loopDuration(0), _lastFrameDuration(0) {} META_Record(Group) META_setID(_group) META_setComment(_group) META_setMultitexture(_group) META_addChild(_group) bool hasAnimation() const { return _forwardAnim || _backwardAnim; } protected: void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); OSG_DEBUG << "ID: " << id << std::endl; /*int16 relativePriority =*/ in.readInt16(); in.forward(2); _flags = in.readUInt32(0); /*uint16 specialId0 =*/ in.readUInt16(); /*uint16 specialId1 =*/ in.readUInt16(); /*uint16 significance =*/ in.readUInt16(); /*int8 layer =*/ in.readInt8(); in.forward(5); // version >= VERSION_15_8 _loopCount = in.readInt32(0); _loopDuration = in.readFloat32(0.0f); _lastFrameDuration = in.readFloat32(0.0f); // Check for forward animation (sequence) _forwardAnim = (_flags & FORWARD_ANIM) != 0; // For versions prior to 15.8, the swing bit can be set independently // of the animation bit. This implies forward animation (with swing) if ((document.version() < VERSION_15_8) && (_flags & SWING_ANIM)) _forwardAnim = true; // OpenFlight 15.8 adds backwards animations _backwardAnim = ( (document.version() >= VERSION_15_8) && ((_flags & BACKWARD_ANIM) != 0) ); if (_forwardAnim || _backwardAnim) _group = new osg::Sequence; else _group = new osg::Group; _group->setName(id); // Add this implementation to parent implementation. if (_parent.valid()) _parent->addChild(*_group); } virtual void dispose(Document& document) { if (!_group.valid()) return; // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_group,*_matrix,_numberOfReplications); } // Children are added! osg::Sequence* sequence = dynamic_cast(_group.get()); if (sequence && sequence->getNumChildren() > 0) { // Regardless of forwards or backwards, animation could have swing bit set. osg::Sequence::LoopMode loopMode = ((_flags & SWING_ANIM) == 0) ? osg::Sequence::LOOP : osg::Sequence::SWING; if (_forwardAnim) sequence->setInterval(loopMode, 0, -1); else sequence->setInterval(loopMode, -1, 0); // Loop timing available from version 15.8. if (document.version() >= VERSION_15_8) { // Set frame duration. float frameDuration = _loopDuration / float(sequence->getNumChildren()); for (unsigned int i=0; i < sequence->getNumChildren(); i++) sequence->setTime(i, frameDuration); // Set number of repetitions. if (_loopCount > 0) sequence->setDuration(1.0f, _loopCount); else sequence->setDuration(1.0f); // Run continuously } else // No timing available. { // Set frame duration float frameDuration = 0.1f; // 10Hz for (unsigned int i=0; i < sequence->getNumChildren(); i++) sequence->setTime(i, frameDuration); // Run continuously sequence->setDuration(1.0f); } sequence->setMode(osg::Sequence::START); } } }; REGISTER_FLTRECORD(Group, GROUP_OP) /** DegreeOfFreedom */ class DegreeOfFreedom : public PrimaryRecord { // Flags static const unsigned long LIMIT_TRANSLATION_X = 0x80000000u >> 0; static const unsigned long LIMIT_TRANSLATION_Y = 0x80000000u >> 1; static const unsigned long LIMIT_TRANSLATION_Z = 0x80000000u >> 2; static const unsigned long LIMIT_PITCH = 0x80000000u >> 3; static const unsigned long LIMIT_ROLL = 0x80000000u >> 4; static const unsigned long LIMIT_YAW = 0x80000000u >> 5; static const unsigned long LIMIT_SCALE_X = 0x80000000u >> 6; static const unsigned long LIMIT_SCALE_Y = 0x80000000u >> 7; static const unsigned long LIMIT_SCALE_Z = 0x80000000u >> 8; struct Range { float64 min; // Minimum value with respect to the local coord system float64 max; // Maximum value with respect to the local coord system float64 current; // Current value with respect to the local coord system float64 increment; // Increment }; osg::ref_ptr _dof; public: DegreeOfFreedom(): _dof(new osgSim::DOFTransform) {} META_Record(DegreeOfFreedom) META_setID(_dof) META_setComment(_dof) META_setMultitexture(_dof) META_addChild(_dof) META_dispose(_dof) protected: virtual ~DegreeOfFreedom() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); in.forward(4); // Reserved osg::Vec3d localOrigin = in.readVec3d(); osg::Vec3d pointOnXAxis = in.readVec3d(); osg::Vec3d pointInXYPlane = in.readVec3d(); Range rangeZ = readRange(in); // Legal z values with respect to the local coord system Range rangeY = readRange(in); // Legal y values with respect to the local coord system Range rangeX = readRange(in); // Legal x values with respect to the local coord system Range rangePitch = readRange(in); // Legal pitch values (rotation about the x-axis) Range rangeRoll = readRange(in); // Legal roll values( rotation about the y-axis) Range rangeYaw = readRange(in); // Legal yaw values (rotation about the z-axis) Range rangeScaleZ = readRange(in); // Legal z scale values (about local origin) Range rangeScaleY = readRange(in); // Legal y scale values about local origin) Range rangeScaleX = readRange(in); // Legal x scale values (about local origin) uint32 flags = in.readUInt32(); // Flags, bits from left to right (see OF doc) // out of range check, required for racecar.flt (Creator Gallery) if (!valid(localOrigin)) localOrigin = osg::Vec3d(0,0,0); if (!valid(pointOnXAxis)) pointOnXAxis = osg::X_AXIS; if (!valid(pointInXYPlane)) pointInXYPlane = osg::Y_AXIS; _dof->setName(id); //tranlsations: _dof->setMinTranslate(osg::Vec3(rangeX.min,rangeY.min,rangeZ.min)*document.unitScale()); _dof->setMaxTranslate(osg::Vec3(rangeX.max,rangeY.max,rangeZ.max)*document.unitScale()); _dof->setCurrentTranslate(osg::Vec3(rangeX.current,rangeY.current,rangeZ.current)*document.unitScale()); _dof->setIncrementTranslate(osg::Vec3(rangeX.increment,rangeY.increment,rangeZ.increment)*document.unitScale()); //rotations: _dof->setMinHPR(osg::Vec3(osg::inDegrees(rangeYaw.min),osg::inDegrees(rangePitch.min),osg::inDegrees(rangeRoll.min))); _dof->setMaxHPR(osg::Vec3(osg::inDegrees(rangeYaw.max),osg::inDegrees(rangePitch.max),osg::inDegrees(rangeRoll.max))); _dof->setCurrentHPR(osg::Vec3(osg::inDegrees(rangeYaw.current),osg::inDegrees(rangePitch.current),osg::inDegrees(rangeRoll.current))); _dof->setIncrementHPR(osg::Vec3(osg::inDegrees(rangeYaw.increment),osg::inDegrees(rangePitch.increment),osg::inDegrees(rangeRoll.increment))); //scales: _dof->setMinScale(osg::Vec3(rangeScaleX.min,rangeScaleY.min,rangeScaleZ.min)); _dof->setMaxScale(osg::Vec3(rangeScaleX.max,rangeScaleY.max,rangeScaleZ.max)); _dof->setCurrentScale(osg::Vec3(rangeScaleX.current,rangeScaleY.current,rangeScaleZ.current)); _dof->setIncrementScale(osg::Vec3(rangeScaleX.increment,rangeScaleY.increment,rangeScaleZ.increment)); // compute axis. osg::Vec3 xAxis = pointOnXAxis - localOrigin; osg::Vec3 xyPlaneVector = pointInXYPlane - localOrigin; osg::Vec3 zAxis = xAxis ^ xyPlaneVector; osg::Vec3 yAxis = zAxis ^ xAxis; // normalize float length_x = xAxis.normalize(); float length_y = yAxis.normalize(); float length_z = zAxis.normalize(); if ((length_x*length_y*length_z)==0.0f) { OSG_NOTICE<<"Warning: OpenFlight DegreeOfFreedom::readRecord() found erroneous axis definition:"<addChild(_impChild0.get(), (float)switchOutDistance * document.unitScale(), (float)switchInDistance * document.unitScale()); // Add this implementation to parent implementation. if (_parent.valid()) _parent->addChild(*_lod); } }; REGISTER_FLTRECORD(LevelOfDetail, LOD_OP) /** OldLevelOfDetail */ class OldLevelOfDetail : public PrimaryRecord { osg::ref_ptr _lod; osg::ref_ptr _impChild0; public: OldLevelOfDetail() {} META_Record(OldLevelOfDetail) META_setID(_lod) META_setComment(_lod) META_setMultitexture(_lod) META_addChild(_impChild0) META_dispose(_lod) protected: virtual ~OldLevelOfDetail() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); uint32 switchInDistance = in.readUInt32(); uint32 switchOutDistance = in.readUInt32(); /*int16 specialEffectID1 =*/ in.readInt16(); /*int16 specialEffectID2 =*/ in.readInt16(); /*uint32 flags =*/ in.readUInt32(); osg::Vec3 center; center.x() = (float)in.readInt32(); center.y() = (float)in.readInt32(); center.z() = (float)in.readInt32(); _lod = new osg::LOD; _lod->setName(id); _lod->setCenter(center*document.unitScale()); _lod->setRange(0, (float)switchOutDistance * document.unitScale(), (float)switchInDistance * document.unitScale()); // Add child to lod. _impChild0 = new osg::Group; _lod->addChild(_impChild0.get()); // Add this implementation to parent implementation. if (_parent.valid()) _parent->addChild(*_lod); } }; REGISTER_FLTRECORD(OldLevelOfDetail, OLD_LOD_OP) /** Switch */ class Switch : public PrimaryRecord { uint32 _currentMask; uint32 _numberOfMasks; uint32 _wordsInMask; std::vector _masks; osg::ref_ptr _multiSwitch; public: Switch() {} META_Record(Switch) META_setID(_multiSwitch) META_setComment(_multiSwitch) META_setMultitexture(_multiSwitch) META_dispose(_multiSwitch) virtual void addChild(osg::Node& child) { if (_multiSwitch.valid()) { unsigned int nChild = _multiSwitch->getNumChildren(); for (unsigned int nMask=0; nMask<_numberOfMasks; ++nMask) { // test if this child is active in the current mask (itMask) unsigned int nMaskBit = nChild % 32; unsigned int nMaskWord = nMask * _wordsInMask + nChild / 32; _multiSwitch->setValue(nMask, nChild, (_masks[nMaskWord] & (uint32(1) << nMaskBit))!=0 ); } _multiSwitch->addChild(&child); } } virtual void setMultiSwitchValueName(unsigned int switchSet, const std::string& name) { if (_multiSwitch.valid()) { _multiSwitch->setValueName(switchSet, name); } } protected: virtual ~Switch() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { std::string id = in.readString(8); in.forward(4); _currentMask = in.readUInt32(); _numberOfMasks = in.readUInt32(); _wordsInMask = in.readUInt32(); _multiSwitch = new osgSim::MultiSwitch; _multiSwitch->setName(id); /* Example: | word #0 || word #1 || word #2 | <- Mask #0 | word #0 || word #1 || word #2 | <- Mask #1 In this example numberOfMasks=2 and wordsInMask=3, currentMask can be 0 or 1. */ for (unsigned int n=0; n<_numberOfMasks*_wordsInMask; n++) { uint32 maskWord = in.readUInt32(); _masks.push_back(maskWord); } _multiSwitch->setActiveSwitchSet(_currentMask); // Add this implementation to parent implementation. if (_parent.valid()) _parent->addChild(*_multiSwitch); } }; REGISTER_FLTRECORD(Switch, SWITCH_OP) /** ExternalReference */ class ExternalReference : public PrimaryRecord { osg::ref_ptr _external; // Parent pool override flags static const unsigned long COLOR_PALETTE_OVERRIDE = 0x80000000u >> 0; static const unsigned long MATERIAL_PALETTE_OVERRIDE = 0x80000000u >> 1; static const unsigned long TEXTURE_PALETTE_OVERRIDE = 0x80000000u >> 2; static const unsigned long LINE_STYLE_PALETTE_OVERRIDE = 0x80000000u >> 3; static const unsigned long SOUND_PALETTE_OVERRIDE = 0x80000000u >> 4; static const unsigned long LIGHT_SOURCE_PALETTE_OVERRIDE = 0x80000000u >> 5; static const unsigned long LIGHT_POINT_PALETTE_OVERRIDE = 0x80000000u >> 6; static const unsigned long SHADER_PALETTE_OVERRIDE = 0x80000000u >> 7; public: ExternalReference() {} META_Record(ExternalReference) META_setID(_external) META_setComment(_external) META_setMultitexture(_external) META_addChild(_external) META_dispose(_external) protected: virtual ~ExternalReference() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string strFile = in.readString(200); _external = new osg::ProxyNode; _external->setCenterMode(osg::ProxyNode::USE_BOUNDING_SPHERE_CENTER); _external->setFileName(0,strFile); // Set parent pools as user data if (document.version() >= VERSION_14_2) { in.forward(4); uint32 mask = in.readUInt32(~0u); // Possible bug in models with version number 15.4.1 ? // Symptoms: Black trees in VegaPlayer town. if (document.version() == 1541) mask = ~0u; ParentPools* parentPools = new ParentPools; if ((mask & COLOR_PALETTE_OVERRIDE) == 0) parentPools->setColorPool(document.getColorPool()); if ((mask & MATERIAL_PALETTE_OVERRIDE) == 0) parentPools->setMaterialPool(document.getMaterialPool()); if ((mask & TEXTURE_PALETTE_OVERRIDE) == 0) parentPools->setTexturePool(document.getTexturePool()); if ((document.version() >= VERSION_15_1) && ((mask & LIGHT_SOURCE_PALETTE_OVERRIDE) == 0)) parentPools->setLightSourcePool(document.getLightSourcePool()); if ((document.version() >= VERSION_15_8) && ((mask & LIGHT_POINT_PALETTE_OVERRIDE) == 0)) parentPools->setLPAppearancePool(document.getLightPointAppearancePool()); if ((document.version() >= VERSION_16_0) && ((mask & SHADER_PALETTE_OVERRIDE) == 0)) parentPools->setShaderPool(document.getShaderPool()); _external->setUserData(parentPools); } // Add this implementation to parent implementation. if (_parent.valid()) _parent->addChild(*_external); } }; REGISTER_FLTRECORD(ExternalReference, EXTERNAL_REFERENCE_OP) /** InstanceDefinition */ class InstanceDefinition : public PrimaryRecord { int _number; osg::ref_ptr _instanceDefinition; public: InstanceDefinition():_number(0) {} META_Record(InstanceDefinition) META_setID(_instanceDefinition) META_setComment(_instanceDefinition) META_setMultitexture(_instanceDefinition) META_addChild(_instanceDefinition) protected: virtual ~InstanceDefinition() {} virtual void readRecord(RecordInputStream& in, Document& document) { in.forward(2); _number = (int)in.readUInt16(); _instanceDefinition = new osg::Group; } virtual void dispose(Document& document) { // Insert transform(s) if (_matrix.valid()) { osg::ref_ptr transform = new osg::MatrixTransform(*_matrix); transform->setDataVariance(osg::Object::STATIC); transform->addChild(_instanceDefinition.get()); _instanceDefinition = transform.get(); } // Add to instance definition table. document.setInstanceDefinition(_number,_instanceDefinition.get()); } }; REGISTER_FLTRECORD(InstanceDefinition, INSTANCE_DEFINITION_OP) /** InstanceReference * The InstanceReference is a leaf record. */ class InstanceReference : public PrimaryRecord { public: InstanceReference() {} META_Record(InstanceReference) protected: virtual ~InstanceReference() {} virtual void readRecord(RecordInputStream& in, Document& document) { in.forward(2); uint16 number = in.readUInt16(); // Get definition. osg::Node* instance = document.getInstanceDefinition(number); // Add this implementation to parent implementation. if (_parent.valid() && instance) _parent->addChild(*instance); } }; REGISTER_FLTRECORD(InstanceReference, INSTANCE_REFERENCE_OP) /** Extension */ class Extension : public PrimaryRecord { osg::ref_ptr _extension; public: Extension() {} META_Record(Extension) META_setID(_extension) META_setComment(_extension) META_setMultitexture(_extension) META_addChild(_extension) META_dispose(_extension) protected: virtual ~Extension() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { std::string id = in.readString(8); std::string siteId = in.readString(8); in.forward(1); _extension = new osg::Group; _extension->setName(id); // Add this implementation to parent implementation. if (_parent.valid()) _parent->addChild(*_extension); } }; REGISTER_FLTRECORD(Extension, EXTENSION_OP) /** Object */ class Object : public PrimaryRecord { static const unsigned int HIDE_IN_DAYLIGHT = 0x80000000u >> 0; static const unsigned int HIDE_AT_DUSK = 0x80000000u >> 1; static const unsigned int HIDE_AT_NIGHT = 0x80000000u >> 2; static const unsigned int NO_ILLUMINATION = 0x80000000u >> 3; static const unsigned int FLAT_SHADED = 0x80000000u >> 4; static const unsigned int SHADOW_OBJECT = 0x80000000u >> 5; osg::ref_ptr _object; public: Object() {} META_Record(Object) META_setID(_object) META_setComment(_object) META_addChild(_object) protected: virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); _object = new osg::Group; _object->setName(id); if (document.getReadObjectRecordData()) { osgSim::ObjectRecordData* ord = new osgSim::ObjectRecordData; ord->_flags = in.readUInt32(); ord->_relativePriority = in.readInt16(); ord->_transparency = in.readUInt16(); ord->_effectID1 = in.readInt16(); ord->_effectID2 = in.readInt16(); ord->_significance = in.readInt16(); _object->setUserData( ord ); } else { /*uint32 flags =*/ in.readUInt32(); } // Postpone add-to-parent until we know a bit more. } virtual void dispose(Document& document) { if (!_parent.valid() || !_object.valid()) return; // Is it safe to remove _object? if (!document.getPreserveObject() && isSafeToRemoveObject() && !_matrix.valid()) { // Add children of _object to parent. // _object will not be added to graph. for (unsigned int i=0; i<_object->getNumChildren(); ++i) { _parent->addChild(*(_object->getChild(i))); } } else { _parent->addChild(*_object); } // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_object,*_matrix,_numberOfReplications); } } bool isSafeToRemoveObject() const { // The following tests need a valid parent. if (_parent.valid()) { // LODs adds an empty child group so it is safe to remove this object record. PrimaryRecord* parent = _parent.get(); if (typeid(parent)==typeid(flt::LevelOfDetail)) return true; if (typeid(parent)==typeid(flt::OldLevelOfDetail)) return true; // If parent is a Group record we have to check for animation. Group* parentGroup = dynamic_cast(parent); if (parentGroup && !parentGroup->hasAnimation()) return true; } return false; } }; REGISTER_FLTRECORD(Object, OBJECT_OP) /** LightSource */ class LightSource : public PrimaryRecord { static const unsigned int ENABLED = 0x80000000u >> 0; static const unsigned int GLOBAL = 0x80000000u >> 1; static const unsigned int EXPORT = 0x80000000u >> 3; osg::ref_ptr _lightSource; public: LightSource() {} META_Record(LightSource) META_setID(_lightSource) META_setComment(_lightSource) META_dispose(_lightSource) protected: virtual ~LightSource() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); in.forward(4); int32 index = in.readInt32(); in.forward(4); uint32 flags = in.readUInt32(); in.forward(4); osg::Vec3d pos = in.readVec3d(); float32 yaw = in.readFloat32(); float32 pitch = in.readFloat32(); _lightSource = new osg::LightSource; _lightSource->setName(id); LightSourcePool* pool = document.getOrCreateLightSourcePool(); osg::Light* lightFromPool = pool->get(index); if (lightFromPool) { // Make a clone of light in pool. osg::Light* light = new osg::Light(*lightFromPool); // TODO: Find a better way to set light number. light->setLightNum(1); // Position float w = lightFromPool->getPosition().w(); if (w > 0.0) // positional light? light->setPosition(osg::Vec4(pos,w)); // Apply yaw and pitch for infinite and spot light. if ((w==0.0) || (light->getSpotCutoff()<180.0)) { // assume yaw is zero along y axis, increase positive clockwise // assume pitch is zero along xy plane, increase positive upwards float cos_yaw = cosf(osg::inDegrees(-yaw)); float sin_yaw = sinf(osg::inDegrees(-yaw)); float cos_pitch = cosf(osg::inDegrees(pitch)); float sin_pitch = sinf(osg::inDegrees(pitch)); light->setDirection(osg::Vec3(sin_yaw*cos_pitch, cos_yaw*cos_pitch, sin_pitch)); } _lightSource->setLight(light); _lightSource->setLocalStateSetModes((flags & ENABLED) ? osg::StateAttribute::ON : osg::StateAttribute::OFF); // Global light. if (flags & GLOBAL) { // Apply light source to header node. osg::Node* header = document.getHeaderNode(); if (header) _lightSource->setStateSetModes(*(header->getOrCreateStateSet()),osg::StateAttribute::ON); } } if (_parent.valid()) _parent->addChild(*_lightSource); } }; REGISTER_FLTRECORD(LightSource, LIGHT_SOURCE_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/LightPointRecords.cpp0000644000175000017500000004160113151044751030153 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" using namespace flt; /** LightPoint */ class LightPoint : public PrimaryRecord { enum Directionality { OMNIDIRECTIONAL = 0, UNIDIRECTIONAL = 1, BIDIRECTIONAL = 2 }; // flags enum Flags { // bit 0 = reserved NO_BACK_COLOR = 0x80000000u >> 1, // bit 1 = no back color // bit 2 = reserved CALLIGRAPHIC = 0x80000000u >> 3, // bit 3 = calligraphic proximity occulting REFLECTIVE = 0x80000000u >> 4, // bit 4 = reflective, non-emissive point // bit 5-7 = randomize intensity // 0 = never // 1 = low // 2 = medium // 3 = high PERSPECTIVE = 0x80000000u >> 8, // bit 8 = perspective mode FLASHING = 0x80000000u >> 9, // bit 9 = flashing ROTATING = 0x80000000u >> 10, // bit 10 = rotating ROTATE_CC = 0x80000000u >> 11, // bit 11 = rotate counter clockwise // bit 12 = reserved // bit 13-14 = quality // 0 = low // 1 = medium // 2 = high // 3 = undefined VISIBLE_DAY = 0x80000000u >> 15, // bit 15 = visible during day VISIBLE_DUSK = 0x80000000u >> 16, // bit 16 = visible during dusk VISIBLE_NIGHT = 0x80000000u >> 17 // bit 17 = visible during night // bit 18-31 = spare }; int16 _material; int16 _feature; osg::Vec4f _backColor; int32 _displayMode; float32 _intensityFront; float32 _intensityBack; float32 _minDefocus; float32 _maxDefocus; int32 _fadeMode; int32 _fogPunchMode; int32 _directionalMode; int32 _rangeMode; float32 _minPixelSize; float32 _maxPixelSize; float32 _actualPixelSize; float32 _transparentFalloff; float32 _transparentFalloffExponent; float32 _transparentFalloffScalar; float32 _transparentFalloffClamp; float32 _fog; float32 _sizeDifferenceThreshold; int32 _directionality; float32 _lobeHorizontal; float32 _lobeVertical; float32 _lobeRoll; float32 _falloff; float32 _ambientIntensity; float32 _animationPeriod; float32 _animationPhaseDelay; float32 _animationPeriodEnable; float32 _significance; int32 _drawOrder; uint32 _flags; osg::Vec3f _animationAxis; osg::ref_ptr _lpn; public: LightPoint() {} META_Record(LightPoint) META_setID(_lpn) META_setComment(_lpn) META_dispose(_lpn) // Add lightpoint, add two if bidirectional. virtual void addVertex(Vertex& vertex) { osgSim::LightPoint lp; lp._position = vertex._coord; lp._radius = 0.5f * _actualPixelSize; lp._intensity = _intensityFront; // color lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1); // sector bool directional = (_directionality==UNIDIRECTIONAL) || (_directionality==BIDIRECTIONAL); if (directional && vertex.validNormal()) { lp._sector = new osgSim::DirectionalSector( vertex._normal, osg::DegreesToRadians(_lobeHorizontal), osg::DegreesToRadians(_lobeVertical), osg::DegreesToRadians(_lobeRoll)); } // if the flashing or rotating bit is set in the flags, add a blink sequence if ((_flags & FLASHING) || (_flags & ROTATING)) { lp._blinkSequence = new osgSim::BlinkSequence(); if (lp._blinkSequence.valid()) { lp._blinkSequence->setDataVariance(osg::Object::DYNAMIC); lp._blinkSequence->setPhaseShift(_animationPhaseDelay); lp._blinkSequence->addPulse(_animationPeriod - _animationPeriodEnable, osg::Vec4f(0.0f, 0.0f, 0.0f, 0.0f)); lp._blinkSequence->addPulse(_animationPeriodEnable, lp._color); } } _lpn->addLightPoint(lp); // Create a new lightpoint if bi-directional. if ((_directionality==BIDIRECTIONAL) && vertex.validNormal()) { // back intensity lp._intensity = _intensityBack; // back color if (!(_flags & NO_BACK_COLOR)) lp._color = _backColor; // back sector lp._sector = new osgSim::DirectionalSector( -vertex._normal, osg::DegreesToRadians(_lobeHorizontal), osg::DegreesToRadians(_lobeVertical), osg::DegreesToRadians(_lobeRoll)); _lpn->addLightPoint(lp); } } protected: virtual ~LightPoint() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); _material = in.readInt16(); _feature = in.readInt16(); int32 backColorIndex = in.readInt32(); _backColor = document.getColorPool() ? document.getColorPool()->getColor(backColorIndex) : osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f); _displayMode = in.readInt32(); _intensityFront = in.readFloat32(); _intensityBack = in.readFloat32(); _minDefocus = in.readFloat32(); _maxDefocus = in.readFloat32(); _fadeMode = in.readInt32(); _fogPunchMode = in.readInt32(); _directionalMode = in.readInt32(); _rangeMode = in.readInt32(); _minPixelSize = in.readFloat32(); // * document.unitScale(); _maxPixelSize = in.readFloat32(); // * document.unitScale(); _actualPixelSize = in.readFloat32(); // * document.unitScale(); _transparentFalloff = in.readFloat32(); _transparentFalloffExponent = in.readFloat32(); _transparentFalloffScalar = in.readFloat32(); _transparentFalloffClamp = in.readFloat32(); _fog = in.readFloat32(); in.forward(4); _sizeDifferenceThreshold = in.readFloat32(); _directionality = in.readInt32(); _lobeHorizontal = in.readFloat32(); _lobeVertical = in.readFloat32(); _lobeRoll = in.readFloat32(); _falloff = in.readFloat32(); _ambientIntensity = in.readFloat32(); _animationPeriod = in.readFloat32(); _animationPhaseDelay = in.readFloat32(); _animationPeriodEnable = in.readFloat32(); _significance = in.readFloat32(); _drawOrder = in.readInt32(); _flags = in.readUInt32(0); _animationAxis = in.readVec3f(); _lpn = new osgSim::LightPointNode; _lpn->setName(id); _lpn->setMinPixelSize(_minPixelSize); _lpn->setMaxPixelSize(_maxPixelSize); // Add to parent if (_parent.valid()) _parent->addChild(*_lpn); } }; REGISTER_FLTRECORD(LightPoint, LIGHT_POINT_OP) /** IndexedLightPoint */ class IndexedLightPoint : public PrimaryRecord { enum Directionality { OMNIDIRECTIONAL = 0, UNIDIRECTIONAL = 1, BIDIRECTIONAL = 2 }; // flags static const unsigned int NO_BACK_COLOR_BIT = 0x80000000u >> 1; osg::ref_ptr _lpn; osg::ref_ptr _appearance; osg::ref_ptr _animation; public: IndexedLightPoint() {} META_Record(IndexedLightPoint) META_setID(_lpn) META_setComment(_lpn) META_dispose(_lpn) // Add lightpoint, add two if bidirectional. virtual void addVertex(Vertex& vertex) { osgSim::LightPoint lp; if (_appearance.valid()) { lp._position = vertex._coord; lp._radius = 0.5f * _appearance->actualPixelSize; lp._intensity = _appearance->intensityFront; // color lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1); // sector bool directional = (_appearance->directionality==UNIDIRECTIONAL) || (_appearance->directionality==BIDIRECTIONAL); if (directional && vertex.validNormal()) { lp._sector = new osgSim::DirectionalSector( vertex._normal, osg::DegreesToRadians(_appearance->horizontalLobeAngle), osg::DegreesToRadians(_appearance->verticalLobeAngle), osg::DegreesToRadians(_appearance->lobeRollAngle)); } // Blink sequence if (_animation.valid()) { osgSim::BlinkSequence* blinkSequence = new osgSim::BlinkSequence; blinkSequence->setName(_animation->name); switch (_animation->animationType) { case LPAnimation::ROTATING: case LPAnimation::STROBE: blinkSequence->setPhaseShift(_animation->animationPhaseDelay); blinkSequence->addPulse(_animation->animationPeriod-_animation->animationEnabledPeriod, osg::Vec4(0,0,0,0)); blinkSequence->addPulse(_animation->animationEnabledPeriod, lp._color); break; case LPAnimation::MORSE_CODE: // todo //blinkSequence->addPulse(double length,lp._color); break; case LPAnimation::FLASHING_SEQUENCE: { blinkSequence->setPhaseShift(_animation->animationPhaseDelay); for (LPAnimation::PulseArray::iterator itr=_animation->sequence.begin(); itr!=_animation->sequence.end(); ++itr) { double duration = itr->duration; osg::Vec4 color; switch (itr->state) { case LPAnimation::ON: color = lp._color; break; case LPAnimation::OFF: color = osg::Vec4(0,0,0,0); break; case LPAnimation::COLOR_CHANGE: color = itr->color; break; } blinkSequence->addPulse(duration, color); } } break; } lp._blinkSequence = blinkSequence; } _lpn->addLightPoint(lp); // Create a new lightpoint if bi-directional. if ((_appearance->directionality==BIDIRECTIONAL) && vertex.validNormal()) { // back intensity lp._intensity = _appearance->intensityBack; // back color if (!(_appearance->flags & NO_BACK_COLOR_BIT)) lp._color = _appearance->backColor; // back sector lp._sector = new osgSim::DirectionalSector( -vertex._normal, osg::DegreesToRadians(_appearance->horizontalLobeAngle), osg::DegreesToRadians(_appearance->verticalLobeAngle), osg::DegreesToRadians(_appearance->lobeRollAngle)); _lpn->addLightPoint(lp); } } } protected: virtual ~IndexedLightPoint() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); int32 appearanceIndex = in.readInt32(); int32 animationIndex = in.readInt32(); /*int32 drawOrder =*/ in.readInt32(); // for calligraphic lights LightPointAppearancePool* lpAppearancePool = document.getOrCreateLightPointAppearancePool(); _appearance = lpAppearancePool->get(appearanceIndex); LightPointAnimationPool* lpAnimationPool = document.getOrCreateLightPointAnimationPool(); _animation = lpAnimationPool->get(animationIndex); _lpn = new osgSim::LightPointNode; _lpn->setName(id); if (_appearance.valid()) { _lpn->setMinPixelSize(_appearance->minPixelSize); _lpn->setMaxPixelSize(_appearance->maxPixelSize); if (_appearance->texturePatternIndex != -1) { // Use point sprites for light points. _lpn->setPointSprite(); TexturePool* tp = document.getOrCreateTexturePool(); osg::StateSet* textureStateSet = tp->get(_appearance->texturePatternIndex); if (textureStateSet) { // Merge face stateset with texture stateset osg::StateSet* stateset = _lpn->getOrCreateStateSet(); stateset->merge(*textureStateSet); } } } // Add to parent if (_parent.valid()) _parent->addChild(*_lpn); } }; REGISTER_FLTRECORD(IndexedLightPoint, INDEXED_LIGHT_POINT_OP) /** LightPointSystem */ class LightPointSystem : public PrimaryRecord { float32 _intensity; int32 _animationState; int32 _flags; osg::ref_ptr _switch; osg::ref_ptr _lps; public: LightPointSystem(): _intensity(1.0f), _animationState(0), _flags(0) {} META_Record(LightPointSystem) META_addChild(_switch) protected: virtual ~LightPointSystem() {} virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); _intensity = in.readFloat32(); _animationState = in.readInt32(0); _flags = in.readInt32(0); _switch = new osgSim::MultiSwitch; _lps = new osgSim::LightPointSystem; _switch->setName(id); _lps->setName(id); _lps->setIntensity(_intensity); switch (_animationState) { // Note that OpenFlight 15.8 spec says 0 means on and 1 means off. // However, if animation is set on in Creator, it stores a 1, and // a zero is stored for off! So, for now, we ignore the spec... case 0: _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_OFF ); break; default: case 1: _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_ON ); break; case 2: _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_RANDOM ); break; } if (_parent.valid()) _parent->addChild(*((osg::Group*)_switch.get())); } virtual void dispose(Document& document) { if (!_switch.valid()) return; // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_switch,*_matrix,_numberOfReplications); } // Set default sets: 0 for all off, 1 for all on _switch->setAllChildrenOff( 0 ); _switch->setAllChildrenOn( 1 ); // set initial on/off state unsigned int initialSet = ( (_flags & 0x80000000) != 0 ) ? 1 : 0; _switch->setActiveSwitchSet( initialSet ); for (unsigned int i = 0; i < _switch->getNumChildren(); i++) { osg::Node* child = _switch->getChild(i); if (osgSim::LightPointNode* lpn = dynamic_cast(child)) lpn->setLightPointSystem(_lps.get()); } } }; REGISTER_FLTRECORD(LightPointSystem, LIGHT_POINT_SYSTEM_OP) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/VertexPaletteManager.cpp0000644000175000017500000003733313151044751030646 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "VertexPaletteManager.h" #include "DataOutputStream.h" #include "Opcodes.h" #include "Utils.h" #include #include #include namespace flt { VertexPaletteManager::VertexPaletteManager( const ExportOptions& fltOpt ) : _currentSizeBytes( 8 ), _current( NULL ), _vertices( NULL ), _fltOpt( fltOpt ) { } VertexPaletteManager::~VertexPaletteManager() { if (!_verticesTempName.empty()) { // Delete our temp file. if (_verticesStr.is_open()) { OSG_WARN << "fltexp: VertexPaletteManager destructor has an open temp file." << std::endl; // This should not happen. FltExportVisitor::complete should close // this file before we get to this destructor. return; } OSG_INFO << "fltexp: Deleting temp file " << _verticesTempName << std::endl; FLTEXP_DELETEFILE( _verticesTempName.c_str() ); } } void VertexPaletteManager::add( const osg::Geometry& geom ) { const osg::Array* v = geom.getVertexArray(); if (!v) { OSG_WARN << "fltexp: Attempting to add NULL vertex array in VertexPaletteManager." << std::endl; return; } const osg::Array* c = geom.getColorArray(); const osg::Array* n = geom.getNormalArray(); const osg::Array* t = geom.getTexCoordArray( 0 ); const unsigned int size = v->getNumElements(); osg::ref_ptr< const osg::Vec3dArray > v3 = asVec3dArray( v, size ); osg::ref_ptr< const osg::Vec4Array > c4 = asVec4Array( c, size ); osg::ref_ptr< const osg::Vec3Array > n3 = asVec3Array( n, size ); osg::ref_ptr< const osg::Vec2Array > t2 = asVec2Array( t, size ); if (v && !v3) return; if (c && !c4) return; if (n && !n3) return; if (t && !t2) return; const bool cpv =( osg::getBinding(geom.getColorArray()) == osg::Array::BIND_PER_VERTEX ); const bool npv =( osg::getBinding(geom.getNormalArray()) == osg::Array::BIND_PER_VERTEX ); add( v, v3.get(), c4.get(), n3.get(), t2.get(), cpv, npv ); } void VertexPaletteManager::add( const osg::Array* key, const osg::Vec3dArray* v, const osg::Vec4Array* c, const osg::Vec3Array* n, const osg::Vec2Array* t, bool colorPerVertex, bool normalPerVertex, bool allowSharing ) { bool needsInit( true ); if (allowSharing) { ArrayMap::iterator it = _arrayMap.find( key ); if (it != _arrayMap.end()) needsInit = false; _current = &( _arrayMap[ key ] ); } else { _current = &( _nonShared ); } if (needsInit) { _current->_byteStart = _currentSizeBytes; _current->_idxCount = v->size(); _current->_idxSizeBytes = recordSize( recordType( v, c, n, t ) ); _currentSizeBytes += ( _current->_idxSizeBytes * _current->_idxCount ); // Next we'll write the vertex palette record data. But, // if we don't have a DataOutputStream yet, open the temp file. if (!_vertices) { _verticesTempName = _fltOpt.getTempDir() + "/ofw_temp_vertices"; _verticesStr.open( _verticesTempName.c_str(), std::ios::out | std::ios::binary ); _vertices = new DataOutputStream( _verticesStr.rdbuf(), _fltOpt.getValidateOnly() ); } writeRecords( v, c, n, t, colorPerVertex, normalPerVertex ); } } unsigned int VertexPaletteManager::byteOffset( unsigned int idx ) const { if (!_current) { OSG_WARN << "fltexp: No current vertex array in VertexPaletteManager." << std::endl; return 4; } if (idx >= _current->_idxCount) { OSG_WARN << "fltexp: Index out of range in VertexPaletteManager." << std::endl; return 4; } return( _current->_byteStart + (_current->_idxSizeBytes * idx) ); } void VertexPaletteManager::write( DataOutputStream& dos ) const { if (_currentSizeBytes == 8) // Empty palette. Don't write anything. return; dos.writeInt16( (int16) VERTEX_PALETTE_OP ); dos.writeUInt16( 8 ); dos.writeInt32( _currentSizeBytes ); // Close the temp file. We're done writing new data to it. _verticesStr.close(); // Open that temp file again, this time for reading. // Then copy to dos. char buf; osgDB::ifstream vertIn; vertIn.open( _verticesTempName.c_str(), std::ios::in | std::ios::binary ); while (!vertIn.eof() ) { vertIn.read( &buf, 1 ); if (vertIn.good()) dos << buf; } vertIn.close(); } VertexPaletteManager::PaletteRecordType VertexPaletteManager::recordType( const osg::Array* v, const osg::Array* c, const osg::Array* n, const osg::Array* t ) { if (t) { // Texture coordinates if (n) return VERTEX_CNT; else return VERTEX_CT; } else { // No texture coordinates if (n) return VERTEX_CN; else return VERTEX_C; } } unsigned int VertexPaletteManager::recordSize( PaletteRecordType recType ) { switch (recType) { case VERTEX_C: return 40; break; case VERTEX_CN: return (_fltOpt.getFlightFileVersionNumber() > ExportOptions::VERSION_15_7) ? 56 : 52; break; case VERTEX_CT: return 48; break; case VERTEX_CNT: return 64; break; default: return 0; } } void VertexPaletteManager::writeRecords( const osg::Vec3dArray* v, const osg::Vec4Array* c, const osg::Vec3Array* n, const osg::Vec2Array* t, bool colorPerVertex, bool normalPerVertex ) { const PaletteRecordType recType = recordType( v, c, n, t ); const int16 sizeBytes = recordSize( recType ); int16 opcode = 0; switch( recType ) { case VERTEX_C: opcode = VERTEX_C_OP; break; case VERTEX_CN: opcode = VERTEX_CN_OP; if (!n) OSG_WARN << "fltexp: VPM::writeRecords: no normal array." << std::endl; break; case VERTEX_CNT: opcode = VERTEX_CNT_OP; if (!n) OSG_WARN << "fltexp: VPM::writeRecords: no normal array." << std::endl; if (!t) OSG_WARN << "fltexp: VPM::writeRecords: no tex coord array." << std::endl; break; case VERTEX_CT: opcode = VERTEX_CT_OP; if (!t) OSG_WARN << "fltexp: VPM::writeRecords: no tex coord array." << std::endl; break; } enum FlagBits { START_HARD_EDGE = (0x8000 >> 0), NORMAL_FROZEN = (0x8000 >> 1), NO_COLOR = (0x8000 >> 2), PACKED_COLOR = (0x8000 >> 3) }; uint32 flags( NO_COLOR ); if (colorPerVertex) flags = PACKED_COLOR; size_t idx; for( idx=0; idxsize(); idx++) { uint32 packedColor( 0 ); if (c && colorPerVertex) { osg::Vec4 color = (*c)[ idx ]; packedColor = (int)(color[3]*255) << 24 | (int)(color[2]*255) << 16 | (int)(color[1]*255) << 8 | (int)(color[0]*255); } // Write fields common to all record types. _vertices->writeInt16( opcode ); _vertices->writeUInt16( sizeBytes ); _vertices->writeUInt16( 0 ); // Color name _vertices->writeInt16( flags ); // Flags _vertices->writeVec3d( (*v)[ idx ] ); // Vertex // Now write record-specific fields. switch( recType ) { case VERTEX_C: { _vertices->writeInt32( packedColor ); // Packed color _vertices->writeUInt32( 0 ); // Vertex color index break; } case VERTEX_CN: { if (!normalPerVertex) // Normal _vertices->writeVec3f( (*n)[ 0 ] ); else _vertices->writeVec3f( (*n)[ idx ] ); _vertices->writeInt32( packedColor ); // Packed color _vertices->writeUInt32( 0 ); // Vertex color index if (_fltOpt.getFlightFileVersionNumber() > ExportOptions::VERSION_15_7) _vertices->writeUInt32( 0 ); // Reserved break; } case VERTEX_CNT: { if (!normalPerVertex) // Normal _vertices->writeVec3f( (*n)[ 0 ] ); else _vertices->writeVec3f( (*n)[ idx ] ); _vertices->writeVec2f( (*t)[ idx ] ); // Tex coord _vertices->writeInt32( packedColor ); // Packed color _vertices->writeUInt32( 0 ); // Vertex color index _vertices->writeUInt32( 0 ); // Reserved break; } case VERTEX_CT: { _vertices->writeVec2f( (*t)[ idx ] ); // Tex coord _vertices->writeInt32( packedColor ); // Packed color _vertices->writeUInt32( 0 ); // Vertex color index break; } } } } osg::ref_ptr< const osg::Vec2Array > VertexPaletteManager::asVec2Array( const osg::Array* in, const unsigned int n ) { if (!in) return NULL; osg::Array::Type arrayType = in->getType(); if (arrayType == osg::Array::Vec2ArrayType) { if (n <= in->getNumElements()) { osg::ref_ptr< const osg::Vec2Array > v2f = dynamic_cast< const osg::Vec2Array* >( in ); return v2f; } } const unsigned int nToCopy = ( (n < in->getNumElements()) ? n : in->getNumElements() ); osg::ref_ptr< osg::Vec2Array > ret = new osg::Vec2Array( n ); switch( arrayType ) { case osg::Array::Vec2ArrayType: { // No need to convert data, but must copy into correctly-sized array. // If the size was correct, we wouldn't be here. osg::ref_ptr< const osg::Vec2Array > v2f = dynamic_cast< const osg::Vec2Array* >( in ); ret->assign( v2f->begin(), v2f->end() );; ret->resize( n ); return ret.get(); } case osg::Array::Vec2dArrayType: { osg::ref_ptr< const osg::Vec2dArray > v2d = dynamic_cast< const osg::Vec2dArray* >( in ); unsigned int idx; for (idx=0; idx VertexPaletteManager::asVec3Array( const osg::Array* in, const unsigned int n ) { if (!in) return NULL; osg::Array::Type arrayType = in->getType(); if (arrayType == osg::Array::Vec3ArrayType) { if (n <= in->getNumElements()) { osg::ref_ptr< const osg::Vec3Array > v3f = dynamic_cast< const osg::Vec3Array* >( in ); return v3f; } } const unsigned int nToCopy = ( (n < in->getNumElements()) ? n : in->getNumElements() ); osg::ref_ptr< osg::Vec3Array > ret = new osg::Vec3Array( n ); switch( arrayType ) { case osg::Array::Vec3ArrayType: { // No need to convert data, but must copy into correctly-sized array. // If the size was correct, we wouldn't be here. osg::ref_ptr< const osg::Vec3Array > v3f = dynamic_cast< const osg::Vec3Array* >( in ); ret->assign( v3f->begin(), v3f->end() );; ret->resize( n ); return ret.get(); } case osg::Array::Vec3dArrayType: { osg::ref_ptr< const osg::Vec3dArray > v3d = dynamic_cast< const osg::Vec3dArray* >( in ); unsigned int idx; for (idx=0; idx VertexPaletteManager::asVec3dArray( const osg::Array* in, const unsigned int n ) { if (!in) return NULL; osg::Array::Type arrayType = in->getType(); if (arrayType == osg::Array::Vec3dArrayType) { if (n <= in->getNumElements()) { osg::ref_ptr< const osg::Vec3dArray > v3d = dynamic_cast< const osg::Vec3dArray* >( in ); return v3d; } } const unsigned int nToCopy = ( (n < in->getNumElements()) ? n : in->getNumElements() ); osg::ref_ptr< osg::Vec3dArray > ret = new osg::Vec3dArray( n ); switch( arrayType ) { case osg::Array::Vec3dArrayType: { // No need to convert data, but must copy into correctly-sized array. // If the size was correct, we wouldn't be here. osg::ref_ptr< const osg::Vec3dArray > v3d = dynamic_cast< const osg::Vec3dArray* >( in ); ret->assign( v3d->begin(), v3d->end() );; ret->resize( n ); return ret.get(); } case osg::Array::Vec3ArrayType: { osg::ref_ptr< const osg::Vec3Array > v3f = dynamic_cast< const osg::Vec3Array* >( in ); unsigned int idx; for (idx=0; idx VertexPaletteManager::asVec4Array( const osg::Array* in, const unsigned int n ) { if (!in) return NULL; osg::Array::Type arrayType = in->getType(); if (arrayType == osg::Array::Vec4ArrayType) { if (n <= in->getNumElements()) { osg::ref_ptr< const osg::Vec4Array > v4f = dynamic_cast< const osg::Vec4Array* >( in ); return v4f; } } const unsigned int nToCopy = ( (n < in->getNumElements()) ? n : in->getNumElements() ); osg::ref_ptr< osg::Vec4Array > ret = new osg::Vec4Array( n ); switch( arrayType ) { case osg::Array::Vec4ArrayType: { // No need to convert data, but must copy into correctly-sized array. // If the size was correct, we wouldn't be here. osg::ref_ptr< const osg::Vec4Array > v4f = dynamic_cast< const osg::Vec4Array* >( in ); ret->assign( v4f->begin(), v4f->end() );; ret->resize( n ); return ret.get(); } case osg::Array::Vec4ubArrayType: { osg::ref_ptr< const osg::Vec4ubArray > v4ub = dynamic_cast< const osg::Vec4ubArray* >( in ); unsigned int idx; for (idx=0; idx #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER // Disable this warning. It's OK for us to use 'this' in initializer list, // as the texturePaletteManager merely stores a ref to it. #pragma warning( disable : 4355 ) #endif namespace flt { FltExportVisitor::FltExportVisitor( DataOutputStream* dos, ExportOptions* fltOpt ) : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ), _fltOpt( fltOpt ), _dos( *dos ), _materialPalette( new MaterialPaletteManager( *fltOpt ) ), _texturePalette( new TexturePaletteManager( *this, *fltOpt ) ), _lightSourcePalette( new LightSourcePaletteManager( ) ), _vertexPalette( new VertexPaletteManager( *fltOpt ) ), _firstNode( true ) { // Init the StateSet stack. osg::StateSet* ss = new osg::StateSet; int unit; for(unit=0; unit<8; unit++) { osg::TexEnv* texenv = new osg::TexEnv; ss->setTextureAttributeAndModes( unit, texenv, osg::StateAttribute::OFF ); // TBD other texture state? } osg::Material* material = new osg::Material; ss->setAttribute( material, osg::StateAttribute::OFF ); if (fltOpt->getLightingDefault()) ss->setMode( GL_LIGHTING, osg::StateAttribute::ON ); else ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); osg::CullFace* cf = new osg::CullFace; ss->setAttributeAndModes( cf, osg::StateAttribute::OFF ); osg::BlendFunc* bf = new osg::BlendFunc; ss->setAttributeAndModes( bf, osg::StateAttribute::OFF ); osg::PolygonOffset* po = new osg::PolygonOffset; ss->setAttributeAndModes( po, osg::StateAttribute::OFF ); _stateSetStack.push_back( ss ); // Temp file for storing records. Need a temp file because we don't // write header and palette until FltExportVisitor completes traversal. _recordsTempName = fltOpt->getTempDir() + "/ofw_temp_records"; _recordsStr.open( _recordsTempName.c_str(), std::ios::out | std::ios::binary ); _records = new DataOutputStream( _recordsStr.rdbuf(), fltOpt->getValidateOnly() ); // Always write initial push level writePush(); } FltExportVisitor::~FltExportVisitor() { // Delete our temp file. if (_recordsStr.is_open()) { OSG_WARN << "fltexp: FltExportVisitor destructor has an open temp file." << std::endl; // This should not happen. FltExportVisitor::complete should close // this file before we get to this destructor. return; } OSG_INFO << "fltexp: Deleting temp file " << _recordsTempName << std::endl; FLTEXP_DELETEFILE( _recordsTempName.c_str() ); } void FltExportVisitor::apply( osg::Group& node ) { ScopedStatePushPop guard( this, node.getStateSet() ); if (_firstNode) { // On input, a FLT header creates a Group node. // On export, we always write a Header record, but then the first Node // we export is the Group that was created from the original input Header. // On successive roundtrips, this results in increased redundant top-level Group nodes/records. // Avoid this by NOT outputting anything for a top-level Group node. _firstNode = false; traverse( node ); return; } // A Group node could indicate one of many possible records. // Header record -- Don't need to support this here. We always output a header. // Group record -- HIGH // Child of an LOD node -- HIGH Currently write out a Group record regardless. // InstanceDefinition/InstanceReference -- MED -- multiparented Group is an instance // Extension record -- MED // Object record -- MED // LightPointSystem record (if psgSim::MultiSwitch) -- LOW osgSim::MultiSwitch* multiSwitch = dynamic_cast( &node ); if (multiSwitch) { writeSwitch( multiSwitch ); } else { osgSim::ObjectRecordData* ord = dynamic_cast< osgSim::ObjectRecordData* >( node.getUserData() ); if (ord) { // This Group should write an Object Record. writeObject( node, ord ); } else { // Handle other cases here. // For now, just output a Group record. writeGroup( node ); } } writeMatrix( node.getUserData() ); writeComment( node ); writePushTraverseWritePop( node ); } void FltExportVisitor::apply( osg::Sequence& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); writeSequence( node ); writeMatrix( node.getUserData() ); writeComment( node ); writePushTraverseWritePop( node ); } void FltExportVisitor::apply( osg::Switch& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); writeSwitch( &node ); writeMatrix( node.getUserData() ); writeComment( node ); writePushTraverseWritePop( node ); } void FltExportVisitor::apply( osg::LOD& lodNode ) { _firstNode = false; ScopedStatePushPop guard( this, lodNode.getStateSet() ); // LOD center - same for all children osg::Vec3d center = lodNode.getCenter(); // Iterate children of the LOD and write a separate LOD record for each, // with that child's individual switchIn and switchOut properties for ( size_t i = 0; i < lodNode.getNumChildren(); ++i ) { osg::Node* lodChild = lodNode.getChild(i); // Switch-in/switch-out distances may vary per child double switchInDist = lodNode.getMaxRange(i); double switchOutDist = lodNode.getMinRange(i); writeLevelOfDetail( lodNode, center, switchInDist, switchOutDist); writeMatrix( lodNode.getUserData() ); writeComment( lodNode ); // Traverse each child of the LOD writePushTraverseChildWritePop( *lodChild ); } } void FltExportVisitor::apply( osg::MatrixTransform& node ) { // Importer reads a Matrix record and inserts a MatrixTransform above // the current node. We need to do the opposite: Write a Matrix record // as an ancillary record for each child. We do that by storing the // MatrixTransform in each child's UserData. Each child then checks // UserData and writes a Matrix record if UserData is a MatrixTransform. _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); osg::ref_ptr< osg::RefMatrix > m = new osg::RefMatrix; m->set( node.getMatrix() ); if (node.getUserData()) { const osg::RefMatrix* rm = dynamic_cast( node.getUserData() ); if (rm) (*m) *= *rm; } typedef std::vector< osg::ref_ptr< osg::Referenced > > UserDataList; UserDataList saveUserDataList( node.getNumChildren() ); unsigned int idx; for( idx=0; idxgetUserData(); node.getChild( idx )->setUserData( m.get() ); } traverse( (osg::Node&)node ); // Restore saved UserData. for( idx=0; idx< node.getNumChildren(); ++idx ) { node.getChild( idx )->setUserData( saveUserDataList[ idx ].get() ); } } void FltExportVisitor::apply( osg::PositionAttitudeTransform& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); osg::ref_ptr m = new osg::RefMatrix( osg::Matrix::translate( -node.getPivotPoint() ) * osg::Matrix::scale( node.getScale() ) * osg::Matrix::rotate( node.getAttitude() ) * osg::Matrix::translate( node.getPosition() ) ); typedef std::vector< osg::ref_ptr< osg::Referenced > > UserDataList; UserDataList saveUserDataList( node.getNumChildren() ); unsigned int idx; for( idx=0; idxgetUserData(); node.getChild( idx )->setUserData( m.get() ); } traverse( (osg::Node&)node ); // Restore saved UserData. for( idx=0; idxsetUserData( saveUserDataList[ idx ].get() ); } } void FltExportVisitor::apply( osg::Transform& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); osgSim::DOFTransform* dof = dynamic_cast( &node ); if (dof) { writeDegreeOfFreedom( dof); } writeMatrix( node.getUserData() ); writeComment( node ); writePushTraverseWritePop( node ); } void FltExportVisitor::apply( osg::LightSource& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); writeLightSource( node ); writeMatrix( node.getUserData() ); writeComment( node ); writePushTraverseWritePop( node ); } // Billboards also go through this code. The Geode is passed // to writeFace and writeMesh. If those methods successfully cast // the Geode to a Billboard, then they set the template mode // bit accordingly. void FltExportVisitor::apply( osg::Geode& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); unsigned int idx; for (idx=0; idxasGeometry(); if (!geom) { std::string warning( "fltexp: Non-Geometry Drawable encountered. Ignoring." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); continue; } ScopedStatePushPop drawableGuard( this, geom->getStateSet() ); // Push and pop subfaces if polygon offset is on. SubfaceHelper subface( *this, getCurrentStateSet() ); if (atLeastOneFace( *geom )) { // If at least one record will be a Face record, then we // need to write to the vertex palette. _vertexPalette->add( *geom ); // Iterate over all PrimitiveSets and output Face records. unsigned int jdx; for (jdx=0; jdx < geom->getNumPrimitiveSets(); jdx++) { osg::PrimitiveSet* prim = geom->getPrimitiveSet( jdx ); if ( isMesh( prim->getMode() ) ) continue; if (prim->getType() == osg::PrimitiveSet::DrawArraysPrimitiveType) handleDrawArrays( dynamic_cast( prim ), *geom, node ); else if (prim->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) handleDrawArrayLengths( dynamic_cast( prim ), *geom, node ); else if ( (prim->getType() == osg::PrimitiveSet::DrawElementsUBytePrimitiveType) || (prim->getType() == osg::PrimitiveSet::DrawElementsUShortPrimitiveType) || (prim->getType() == osg::PrimitiveSet::DrawElementsUIntPrimitiveType) ) handleDrawElements( dynamic_cast( prim ), *geom, node ); else { std::string warning( "fltexp: Unknown PrimitiveSet type." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } } } if (atLeastOneMesh( *geom )) { // If at least one Mesh record, write out preamble mesh records // followed by a Mesh Primitive record per PrimitiveSet. writeMesh( node, *geom ); writeMatrix( node.getUserData() ); writeComment( node ); writeMultitexture( *geom ); writeLocalVertexPool( *geom ); writePush(); unsigned int jdx; for (jdx=0; jdx < geom->getNumPrimitiveSets(); jdx++) { osg::PrimitiveSet* prim = geom->getPrimitiveSet( jdx ); if ( !isMesh( prim->getMode() ) ) continue; if (prim->getType() == osg::PrimitiveSet::DrawArraysPrimitiveType) handleDrawArrays( dynamic_cast( prim ), *geom, node ); else if (prim->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) handleDrawArrayLengths( dynamic_cast( prim ), *geom, node ); else if ( (prim->getType() == osg::PrimitiveSet::DrawElementsUBytePrimitiveType) || (prim->getType() == osg::PrimitiveSet::DrawElementsUShortPrimitiveType) || (prim->getType() == osg::PrimitiveSet::DrawElementsUIntPrimitiveType) ) handleDrawElements( dynamic_cast( prim ), *geom, node ); else { std::string warning( "fltexp: Unknown PrimitiveSet type." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } } writePop(); } } // Would traverse here if this node could have children. // traverse( (osg::Node&)node ); } void FltExportVisitor::apply( osg::Node& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); osgSim::LightPointNode* lpn = dynamic_cast< osgSim::LightPointNode* >( &node ); if (lpn) { writeLightPoint( lpn ); } else { // Unknown Node. Warn and return. // (Note, if the base class of this Node was a Group, then apply(Group&) // would export a Group record then continue traversal. Because we are // a Node, there's no way to continue traversal, so just return.) std::string warning( "fltexp: Unknown Node in OpenFlight export." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } } void FltExportVisitor::apply( osg::ProxyNode& node ) { _firstNode = false; ScopedStatePushPop guard( this, node.getStateSet() ); writeExternalReference( node ); writeMatrix( node.getUserData() ); writeComment( node ); } bool FltExportVisitor::complete( const osg::Node& node ) { // Always write final pop level writePop(); // Done writing records, close the record data temp file. _recordsStr.close(); // Write OpenFlight file front matter: header, vertex palette, etc. writeHeader( node.getName() ); writeColorPalette(); _materialPalette->write( _dos ); _texturePalette->write( _dos ); _lightSourcePalette->write( _dos ); _vertexPalette->write( _dos ); // Write Comment ancillary record and specify the _dos DataOutputStream. writeComment( node, &_dos ); // Copy record data temp file into final OpenFlight file. // Yee-uck. TBD need better stream copy routine. char buf; osgDB::ifstream recIn; recIn.open( _recordsTempName.c_str(), std::ios::in | std::ios::binary ); while (!recIn.eof() ) { recIn.read( &buf, 1 ); if (recIn.good()) _dos << buf; } recIn.close(); return true; } // // StateSet stack support void FltExportVisitor::pushStateSet( const osg::StateSet* rhs ) { osg::StateSet* ss = new osg::StateSet( *( _stateSetStack.back().get() ) ); if (rhs) ss->merge( *rhs ); _stateSetStack.push_back( ss ); } void FltExportVisitor::popStateSet() { _stateSetStack.pop_back(); } const osg::StateSet* FltExportVisitor::getCurrentStateSet() const { return _stateSetStack.back().get(); } void FltExportVisitor::clearStateSetStack() { _stateSetStack.clear(); } void FltExportVisitor::writeATTRFile( int unit, const osg::Texture2D* texture ) const { std::string name; if (_fltOpt->getStripTextureFilePath()) name = osgDB::getSimpleFileName( texture->getImage()->getFileName() ); else name = texture->getImage()->getFileName(); name += std::string( ".attr" ); if ( osgDB::findDataFile( name ).empty() ) { // No .attr file found. We should write one out. // Fill AttrData fields from current state. AttrData ad; ad.texels_u = texture->getImage()->s(); ad.texels_v = texture->getImage()->t(); switch( texture->getFilter( osg::Texture::MIN_FILTER ) ) { case osg::Texture::LINEAR: ad.minFilterMode = AttrData::MIN_FILTER_BILINEAR; break; case osg::Texture::LINEAR_MIPMAP_LINEAR: ad.minFilterMode = AttrData::MIN_FILTER_MIPMAP_TRILINEAR; break; case osg::Texture::LINEAR_MIPMAP_NEAREST: ad.minFilterMode = AttrData::MIN_FILTER_MIPMAP_BILINEAR; break; case osg::Texture::NEAREST: ad.minFilterMode = AttrData::MIN_FILTER_POINT; break; case osg::Texture::NEAREST_MIPMAP_LINEAR: ad.minFilterMode = AttrData::MIN_FILTER_MIPMAP_LINEAR; break; case osg::Texture::NEAREST_MIPMAP_NEAREST: ad.minFilterMode = AttrData::MIN_FILTER_MIPMAP_POINT; break; default: ad.minFilterMode = AttrData::MIN_FILTER_MIPMAP_TRILINEAR; break; } switch( texture->getFilter( osg::Texture::MAG_FILTER ) ) { case osg::Texture::NEAREST: ad.magFilterMode = AttrData::MAG_FILTER_POINT; break; default: ad.magFilterMode = AttrData::MAG_FILTER_BILINEAR; break; } // Repeat and Clamp switch( texture->getWrap( osg::Texture::WRAP_S ) ) { case osg::Texture::CLAMP: case osg::Texture::CLAMP_TO_EDGE: case osg::Texture::CLAMP_TO_BORDER: ad.wrapMode_u = AttrData::WRAP_CLAMP; break; case osg::Texture::REPEAT: default: ad.wrapMode_u = AttrData::WRAP_REPEAT; break; case osg::Texture::MIRROR: if (_fltOpt->getFlightFileVersionNumber() >= 1610) ad.wrapMode_u = AttrData::WRAP_MIRRORED_REPEAT; else ad.wrapMode_u = AttrData::WRAP_REPEAT; break; } switch( texture->getWrap( osg::Texture::WRAP_T ) ) { case osg::Texture::CLAMP: case osg::Texture::CLAMP_TO_EDGE: case osg::Texture::CLAMP_TO_BORDER: ad.wrapMode_v = AttrData::WRAP_CLAMP; break; case osg::Texture::REPEAT: default: ad.wrapMode_v = AttrData::WRAP_REPEAT; break; case osg::Texture::MIRROR: if (_fltOpt->getFlightFileVersionNumber() >= 1610) ad.wrapMode_v = AttrData::WRAP_MIRRORED_REPEAT; else ad.wrapMode_v = AttrData::WRAP_REPEAT; break; } const osg::StateSet* ss = getCurrentStateSet(); const osg::TexEnv* texenv = dynamic_cast( ss->getTextureAttribute( unit, osg::StateAttribute::TEXENV ) ); if (texenv) { switch( texenv->getMode()) { case osg::TexEnv::DECAL: ad.texEnvMode = AttrData::TEXENV_DECAL; break; case osg::TexEnv::MODULATE: default: ad.texEnvMode = AttrData::TEXENV_MODULATE; break; case osg::TexEnv::BLEND: ad.texEnvMode = AttrData::TEXENV_BLEND; break; case osg::TexEnv::REPLACE: ad.texEnvMode = AttrData::TEXENV_COLOR; break; case osg::TexEnv::ADD: ad.texEnvMode = AttrData::TEXENV_ADD; break; } } osgDB::writeObjectFile( ad, name, _fltOpt.get() ); } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/ReaderWriterATTR.cpp0000644000175000017500000002322213151044751027641 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight(R) loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include #include #include #include #include "AttrData.h" #include "DataInputStream.h" #include "DataOutputStream.h" using namespace osg; using namespace osgDB; using namespace flt; class ReaderWriterATTR : public osgDB::ReaderWriter { public: ReaderWriterATTR() { supportsExtension("attr","OpenFlight texture attribute format"); } virtual const char* className() const { return "ATTR Image Attribute Reader/Writer"; } virtual bool acceptsExtension(const std::string& extension) const { return equalCaseInsensitive(extension,"attr"); } virtual ReadResult readObject(const std::string& fileName, const ReaderWriter::Options*) const; virtual ReaderWriter::WriteResult writeObject(const osg::Object& object, const std::string& fileName, const Options* options) const; }; ReaderWriter::ReadResult ReaderWriterATTR::readObject(const std::string& file, const ReaderWriter::Options* options) const { using std::ios; std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osgDB::ifstream fin; fin.imbue(std::locale::classic()); fin.open(fileName.c_str(), std::ios::in | std::ios::binary); if ( fin.fail()) return ReadResult::ERROR_IN_READING_FILE; flt::DataInputStream in(fin.rdbuf()); AttrData* attr = new AttrData; attr->texels_u = in.readInt32(); attr->texels_v = in.readInt32(); attr->direction_u = in.readInt32(); attr->direction_v = in.readInt32(); attr->x_up = in.readInt32(); attr->y_up = in.readInt32(); attr->fileFormat = in.readInt32(); attr->minFilterMode = in.readInt32(); attr->magFilterMode = in.readInt32(); attr->wrapMode = in.readInt32(AttrData::WRAP_REPEAT); attr->wrapMode_u = in.readInt32(); if (attr->wrapMode_u == AttrData::WRAP_NONE) attr->wrapMode_u = attr->wrapMode; attr->wrapMode_v = in.readInt32(); if (attr->wrapMode_v == AttrData::WRAP_NONE) attr->wrapMode_v = attr->wrapMode; attr->modifyFlag = in.readInt32(); attr->pivot_x = in.readInt32(); attr->pivot_y = in.readInt32(); // v11 ends here // if (in.eof() || (_flt_version <= 11)) return true; #if 1 attr->texEnvMode = in.readInt32(AttrData::TEXENV_MODULATE); attr->intensityAsAlpha = in.readInt32(); in.forward(4*8); in.forward(4); attr->size_u = in.readFloat64(); attr->size_v = in.readFloat64(); attr->originCode = in.readInt32(); attr->kernelVersion = in.readInt32(); attr->intFormat = in.readInt32(); attr->extFormat = in.readInt32(); attr->useMips = in.readInt32(); for (int n=0; n<8; n++) attr->of_mips[n] = in.readFloat32(); attr->useLodScale = in.readInt32(); attr->lod0 = in.readFloat32(); attr->scale0 = in.readFloat32(); attr->lod1 = in.readFloat32(); attr->scale1 = in.readFloat32(); attr->lod2 = in.readFloat32(); attr->scale2 = in.readFloat32(); attr->lod3 = in.readFloat32(); attr->scale3 = in.readFloat32(); attr->lod4 = in.readFloat32(); attr->scale4 = in.readFloat32(); attr->lod5 = in.readFloat32(); attr->scale5 = in.readFloat32(); attr->lod6 = in.readFloat32(); attr->scale6 = in.readFloat32(); attr->lod7 = in.readFloat32(); attr->scale7 = in.readFloat32(); attr->clamp = in.readFloat32(); attr->magFilterAlpha = in.readInt32(); attr->magFilterColor = in.readInt32(); in.forward(4); in.forward(4*8); attr->lambertMeridian = in.readFloat64(); attr->lambertUpperLat = in.readFloat64(); attr->lambertlowerLat = in.readFloat64(); in.forward(8); in.forward(4*5); attr->useDetail = in.readInt32( ); attr->txDetail_j = in.readInt32(); attr->txDetail_k = in.readInt32(); attr->txDetail_m = in.readInt32(); attr->txDetail_n = in.readInt32(); attr->txDetail_s = in.readInt32( ); attr->useTile = in.readInt32(); attr->txTile_ll_u= in.readFloat32(); attr->txTile_ll_v = in.readFloat32(); attr->txTile_ur_u = in.readFloat32(); attr->txTile_ur_v = in.readFloat32(); attr->projection = in.readInt32(); attr->earthModel = in.readInt32(); in.forward(4); attr->utmZone = in.readInt32(); attr->imageOrigin = in.readInt32(); attr->geoUnits = in.readInt32(); in.forward(4); in.forward(4); attr->hemisphere = in.readInt32(); in.forward(4); in.forward(4); in.forward(149*4); attr->comments = in.readString(512); // v12 ends here // if (in.eof() || (_flt_version <= 12)) return true; in.forward(14*4); attr->attrVersion = in.readInt32(); attr->controlPoints = in.readInt32(); attr->numSubtextures = in.readInt32(); #endif fin.close(); return attr; } ReaderWriter::WriteResult ReaderWriterATTR::writeObject(const osg::Object& object, const std::string& fileName, const Options* options) const { using std::ios; std::string ext = osgDB::getLowerCaseFileExtension( fileName ); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; const AttrData* attr = dynamic_cast< const AttrData* >( &object ); if (attr == NULL) { OSG_FATAL << "AttrWriter: Invalid Object." << std::endl; return WriteResult::FILE_NOT_HANDLED; } osgDB::ofstream fOut; fOut.open( fileName.c_str(), std::ios::out | std::ios::binary ); if ( fOut.fail()) return WriteResult::ERROR_IN_WRITING_FILE; flt::DataOutputStream out( fOut.rdbuf() ); out.writeInt32( attr->texels_u ); out.writeInt32( attr->texels_v ); out.writeInt32( attr->direction_u ); out.writeInt32( attr->direction_v ); out.writeInt32( attr->x_up ); out.writeInt32( attr->y_up ); out.writeInt32( attr->fileFormat ); out.writeInt32( attr->minFilterMode ); out.writeInt32( attr->magFilterMode ); out.writeInt32( attr->wrapMode ); out.writeInt32( attr->wrapMode_u ); out.writeInt32( attr->wrapMode_v ); out.writeInt32( attr->modifyFlag ); out.writeInt32( attr->pivot_x ); out.writeInt32( attr->pivot_y ); out.writeInt32( attr->texEnvMode ); out.writeInt32( attr->intensityAsAlpha ); out.writeFill( 4*8 ); out.writeFloat64( attr->size_u ); out.writeFloat64( attr->size_v ); out.writeInt32( attr->originCode ); out.writeInt32( attr->kernelVersion ); out.writeInt32( attr->intFormat ); out.writeInt32( attr->extFormat ); out.writeInt32( attr->useMips ); for (int n=0; n<8; n++) out.writeFloat32( attr->of_mips[n] ); out.writeInt32( attr->useLodScale ); out.writeFloat32( attr->lod0 ); out.writeFloat32( attr->scale0 ); out.writeFloat32( attr->lod1 ); out.writeFloat32( attr->scale1 ); out.writeFloat32( attr->lod2 ); out.writeFloat32( attr->scale2 ); out.writeFloat32( attr->lod3 ); out.writeFloat32( attr->scale3 ); out.writeFloat32( attr->lod4 ); out.writeFloat32( attr->scale4 ); out.writeFloat32( attr->lod5 ); out.writeFloat32( attr->scale5 ); out.writeFloat32( attr->lod6 ); out.writeFloat32( attr->scale6 ); out.writeFloat32( attr->lod7 ); out.writeFloat32( attr->scale7 ); out.writeFloat32( attr->clamp ); out.writeInt32( attr->magFilterAlpha ); out.writeInt32( attr->magFilterColor ); out.writeFill( 4 ); out.writeFill( 4*8 ); out.writeFloat64( attr->lambertMeridian ); out.writeFloat64( attr->lambertUpperLat ); out.writeFloat64( attr->lambertlowerLat ); out.writeFill( 8 ); out.writeFill( 4*5 ); out.writeInt32( attr->useDetail ); out.writeInt32( attr->txDetail_j ); out.writeInt32( attr->txDetail_k ); out.writeInt32( attr->txDetail_m ); out.writeInt32( attr->txDetail_n ); out.writeInt32( attr->txDetail_s ); out.writeInt32( attr->useTile ); out.writeFloat32( attr->txTile_ll_u ); out.writeFloat32( attr->txTile_ll_v ); out.writeFloat32( attr->txTile_ur_u ); out.writeFloat32( attr->txTile_ur_v ); out.writeInt32( attr->projection ); out.writeInt32( attr->earthModel ); out.writeFill( 4 ); out.writeInt32( attr->utmZone ); out.writeInt32( attr->imageOrigin ); out.writeInt32( attr->geoUnits ); out.writeFill( 4 ); out.writeFill( 4 ); out.writeInt32( attr->hemisphere ); out.writeFill( 4 ); out.writeFill( 4 ); out.writeFill( 149*4 ); out.writeString( attr->comments, 512 ); out.writeFill( 13*4 ); out.writeInt32( attr->attrVersion ); out.writeInt32( attr->controlPoints ); out.writeInt32( attr->numSubtextures ); fOut.close(); return WriteResult::FILE_SAVED; } // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(attr, ReaderWriterATTR) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/DataInputStream.cpp0000644000175000017500000001055513151044751027621 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include "DataInputStream.h" #include #include using namespace flt; DataInputStream::DataInputStream(std::streambuf* sb): std::istream(sb) { _byteswap = osg::getCpuByteOrder() == osg::LittleEndian; } int8 DataInputStream::readInt8(int8 def) { int8 d; read((char*)&d, sizeof(int8)); if (!good()) return def; return d; } uint8 DataInputStream::readUInt8(uint8 def) { uint8 d; read((char*)&d, sizeof(uint8)); if (!good()) return def; return d; } int16 DataInputStream::readInt16(int16 def) { int16 d; read((char*)&d, sizeof(int16)); if (!good()) return def; if (_byteswap) osg::swapBytes2((char *)&d); return d; } uint16 DataInputStream::readUInt16(uint16 def) { uint16 d; read((char*)&d, sizeof(uint16)); if (!good()) return def; if (_byteswap) osg::swapBytes2((char *)&d); return d; } int32 DataInputStream::readInt32(int32 def) { int32 d; read((char*)&d, sizeof(int32)); if (!good()) return def; if (_byteswap) osg::swapBytes4((char *)&d); return d; } uint32 DataInputStream::readUInt32(uint32 def) { uint32 d; read((char*)&d, sizeof(uint32)); if (!good()) return def; if (_byteswap) osg::swapBytes4((char *)&d); return d; } float32 DataInputStream::readFloat32(float32 def) { float32 d; read((char*)&d, sizeof(float32)); if (!good()) return def; if (_byteswap) osg::swapBytes4((char*)&d); return d; } float64 DataInputStream::readFloat64(float64 def) { float64 d; read((char*)&d, sizeof(float64)); if (!good()) return def; if (_byteswap) osg::swapBytes8((char*)&d); return d; } void DataInputStream::readCharArray(char* data, int size) { read(data,size); } std::string DataInputStream::readString(int size) { char* buf = new char[size+1]; read(buf,size); buf[size] = '\0'; std::string str = buf; delete [] buf; return str; } osg::Vec4f DataInputStream::readColor32() { uint8 alpha = readUInt8(); uint8 blue = readUInt8(); uint8 green = readUInt8(); uint8 red = readUInt8(); osg::Vec4f color((float)red/255,(float)green/255,(float)blue/255,(float)alpha/255); return color; } osg::Vec2f DataInputStream::readVec2f() { float32 x = readFloat32(); float32 y = readFloat32(); osg::Vec2f vec(x,y); return vec; } osg::Vec3f DataInputStream::readVec3f() { float32 x = readFloat32(); float32 y = readFloat32(); float32 z = readFloat32(); osg::Vec3f vec(x,y,z); return vec; } osg::Vec4f DataInputStream::readVec4f() { float32 x = readFloat32(); float32 y = readFloat32(); float32 z = readFloat32(); float32 w = readFloat32(); osg::Vec4f vec(x,y,z,w); return vec; } osg::Vec3d DataInputStream::readVec3d() { float64 x = readFloat64(); float64 y = readFloat64(); float64 z = readFloat64(); osg::Vec3d vec(x,y,z); return vec; } int16 DataInputStream::peekInt16() { // Get current read position in stream. std::istream::pos_type pos = tellg(); int16 value = readInt16(); // Restore position seekg(pos, std::ios_base::beg); return value; } std::istream& DataInputStream::forward(std::istream::off_type off) { //return vforward(off); return seekg(off, std::ios_base::cur); } #if 0 std::istream& DataInputStream::vread(char_type *str, std::streamsize count) { return read(str,count); } std::istream& DataInputStream::vforward(std::istream::off_type off) { return seekg(off, std::ios_base::cur); } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Registry.cpp0000644000175000017500000000275113151044751026363 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include "Registry.h" using namespace flt; Registry::Registry() { } Registry::~Registry() { } Registry* Registry::instance() { static Registry s_registry; return &s_registry; } void Registry::addPrototype(int opcode, Record* prototype) { if (prototype==0L) { OSG_WARN << "Not a record." << std::endl; return; } if (_recordProtoMap.find(opcode) != _recordProtoMap.end()) OSG_WARN << "Registry already contains prototype for opcode " << opcode << "." << std::endl; _recordProtoMap[opcode] = prototype; } Record* Registry::getPrototype(int opcode) { RecordProtoMap::iterator itr = _recordProtoMap.find(opcode); if (itr != _recordProtoMap.end()) return (*itr).second.get(); return NULL; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Utils.h0000644000175000017500000000175513151044751025323 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_UTILS_H__ #define __FLTEXP_UTILS_H__ 1 // FLTEXP_DELETEFILE macro is used to delete temp files created during file export. // (Too bad OSG doesn't use Boost.) #if defined(_WIN32) #include #define FLTEXP_DELETEFILE(file) DeleteFile((file)) #else // Unix #include #define FLTEXP_DELETEFILE(file) remove((file)) #endif #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/AttrData.h0000644000175000017500000004043213151044751025722 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_ATTRDATA_H #define FLT_ATTRDATA_H #include #include #include "Types.h" namespace flt { class AttrData : public osg::Object { public : AttrData(); AttrData(const AttrData& attr, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); META_Object(flt,AttrData); enum MinFilterMode { MIN_FILTER_POINT = 0, MIN_FILTER_BILINEAR = 1, MIN_FILTER_MIPMAP = 2, // (Obsolete) MIN_FILTER_MIPMAP_POINT = 3, MIN_FILTER_MIPMAP_LINEAR = 4, MIN_FILTER_MIPMAP_BILINEAR = 5, MIN_FILTER_MIPMAP_TRILINEAR = 6, MIN_FILTER_NONE = 7, MIN_FILTER_BICUBIC = 8, MIN_FILTER_BILINEAR_GEQUAL = 9, MIN_FILTER_BILINEAR_LEQUAL = 10, MIN_FILTER_BICUBIC_GEQUAL = 11, MIN_FILTER_BICUBIC_LEQUAL = 12 }; enum MagFilterMode { MAG_FILTER_POINT = 0, MAG_FILTER_BILINEAR = 1, MAG_FILTER_NONE = 2, MAG_FILTER_BICUBIC = 3, MAG_FILTER_SHARPEN = 4, MAG_FILTER_ADD_DETAIL = 5, MAG_FILTER_MODULATE_DETAIL = 6, MAG_FILTER_BILINEAR_GEQUAL = 7, MAG_FILTER_BILINEAR_LEQUAL = 8, MAG_FILTER_BICUBIC_GEQUAL = 9, MAG_FILTER_BICUBIC_LEQUAL = 10 }; enum WrapMode { WRAP_REPEAT = 0, WRAP_CLAMP = 1, WRAP_NONE = 3, WRAP_MIRRORED_REPEAT = 4 }; enum TexEnvMode { TEXENV_MODULATE = 0, TEXENV_BLEND = 1, TEXENV_DECAL = 2, TEXENV_COLOR = 3, TEXENV_ADD = 4 }; enum Projection { PROJECTION_FLAT = 0, PROJECTION_LAMBERT_CONIC = 3, PROJECTION_UTM = 4, PROJECTION_UNDEFINED = 7 }; enum Datum { DATUM_WGS84 = 0, DATUM_WGS72 = 1, DATUM_BESSEL = 2, DATUM_CLARK_1866 = 3, DATUM_NAD27 = 4 }; enum InternalFormat { INTERNAL_FORMAT_DEFAULT = 0, INTERNAL_FORMAT_TX_I_12A_4 = 1, INTERNAL_FORMAT_TX_IA_8 = 2, INTERNAL_FORMAT_TX_RGB_5 = 3, INTERNAL_FORMAT_TX_RGBA_4 = 4, INTERNAL_FORMAT_TX_IA_12 = 5, INTERNAL_FORMAT_TX_RGBA_8 = 6, INTERNAL_FORMAT_TX_RGBA_12 = 7, INTERNAL_FORMAT_TX_I_16 = 8, INTERNAL_FORMAT_TX_RGB_12 = 9 }; int32 texels_u; // Number of texels in u direction int32 texels_v; // Number of texels in v direction int32 direction_u; // Real world size u direction int32 direction_v; // Real world size v direction int32 x_up; // x component of up vector int32 y_up; // y component of up vector int32 fileFormat; // File format type // -1 Not used // 0 AT&T image 8 pattern // 1 AT&T image 8 template // 2 SGI intensity modulation // 3 SGI intensity w/ alpha // 4 SGI RGB // 5 SGI RGB w/ alpha int32 minFilterMode; // Minification filter type // 0 - TX_POINT // 1 - TX_BILINEAR // 2 - TX_MIPMAP (Obsolete) // 3 - TX_MIPMAP_POINT // 4 - TX_MIPMAP_LINEAR // 5 - TX_MIPMAP_BILINEAR // 6 - TX_MIPMAP_TRILINEAR // 7 - None // 8 - TX_BICUBIC // 9 - TX_BILINEAR_GEQUAL // 10 - TX_BILINEAR_LEQUAL // 11 - TX_BICUBIC_GEQUAL // 12 - TX_BICUBIC_LEQUAL int32 magFilterMode; // Magnification filter type // 0 - TX_POINT // 1 - TX_BILINEAR // 2 - None // 3 - TX_BICUBIC // 4 - TX_SHARPEN // 5 - TX_ADD_DETAIL // 6 - TX_MODULATE_DETAIL // 7 - TX_BILINEAR_GEQUAL // 8 - TX_BILINEAR_LEQUAL // 9 - TX_BICUBIC_GEQUAL // 10 - TX_BICUBIC_LEQUAL int32 wrapMode; // Repetition type // 0 - TX_REPEAT // 1 - TX_CLAMP // 2 - (Obsolete) int32 wrapMode_u; // Repetition type in u direction (see above) int32 wrapMode_v; // Repetition type in v direction (see above) int32 modifyFlag; // Modify flag (for internal use) int32 pivot_x; // x pivot point for rotating textures int32 pivot_y; // y pivot point for rotating textures // -------------- // v11 ends here // -------------- int32 texEnvMode; // Environment type // 0 - TV_MODULATE // 1 - TV_BLEND // 2 - TV_DECAL // 3 - TV_COLOR // 4 - TV_ADD int32 intensityAsAlpha; // TRUE if intensity pattern to be loaded in alpha with white in color // int32 spare1[8]; // 8 words of spare float64 size_u; // Real world size u for floating point databases float64 size_v; // Real world size v for floating point databases int32 originCode; // Code for origin of imported texture int32 kernelVersion; // Kernel version number int32 intFormat; // Internal format type // 0 - Default // 1 - TX_I_12A_4 // 2 - TX_IA_8 // 3 - TX_RGB_5 // 4 - TX_RGBA_4 // 5 - TX_IA_12 // 6 - TX_RGBA_8 // 7 - TX_RGBA_12 // 8 - TX_I_16 (shadow mode only) // 9 - TX_RGB_12 int32 extFormat; // External format type // 0 - Default // 1 - TX_PACK_8 // 2 - TX_PACK_16 int32 useMips; // TRUE if using following 8 floats for MIPMAP kernel float32 of_mips[8]; // 8 floats for kernel of separable symmetric filter int32 useLodScale; // Boolean if TRUE send: float32 lod0; // LOD0 for TX_CONTROL_POINT float32 scale0; // SCALE0 for TX_CONTROL_POINT float32 lod1; // LOD1 for TX_CONTROL_POINT float32 scale1; // SCALE1 for TX_CONTROL_POINT float32 lod2; // LOD2 for TX_CONTROL_POINT float32 scale2; // SCALE2 for TX_CONTROL_POINT float32 lod3; // LOD3 for TX_CONTROL_POINT float32 scale3; // SCALE3 for TX_CONTROL_POINT float32 lod4; // LOD4 for TX_CONTROL_POINT float32 scale4; // SCALE4 for TX_CONTROL_POINT float32 lod5; // LOD5 for TX_CONTROL_POINT float32 scale5; // SCALE5 for TX_CONTROL_POINT float32 lod6; // LOD6 for TX_CONTROL_POINT float32 scale6; // SCALE6 for TX_CONTROL_POINT float32 lod7; // LOD7 for TX_CONTROL_POINT float32 scale7; // SCALE7 for TX_CONTROL_POINT float32 clamp; // Clamp int32 magFilterAlpha; // magfilteralpha: // 0 = TX_POINT // 1 = TX_BILINEAR // 2 = None // 3 = TX_BICUBIC // 4 = TX_SHARPEN // 5 = TX_ADD_DETAIL // 6 = TX_MODULATE_DETAIL // 7 = TX_BILINEAR_GEQUAL // 8 = TX_BILINEAR_LEQUAL // 9 = TX_BICUBIC_GEQUAL // 10 = TX_BIBICUBIC_LEQUAL int32 magFilterColor; // magfiltercolor: // 0 = TX_POINT // 1 = TX_BILINEAR // 2 = None // 3 = TX_BICUBIC // 4 = TX_SHARPEN // 5 = TX_ADD_DETAIL // 6 = TX_MODULATE_DETAIL // 7 = TX_BILINEAR_GEQUAL // 8 = TX_BILINEAR_LEQUAL // 9 = TX_BICUBIC_GEQUAL // 10 = TX_BIBICUBIC_LEQUAL // float32 reserved1; // Reserved // float32 reserved2[8]; // Reserved float64 lambertMeridian; // Lambert conic projection central meridian float64 lambertUpperLat; // Lambert conic projection upper latitude float64 lambertlowerLat; // Lambert conic projection lower latitude // float64 reserved3; // Reserved // float32 spare2[5]; // Spare int32 useDetail; // TRUE if using next 5 integers for detail texture int32 txDetail_j; // J argument for TX_DETAIL int32 txDetail_k; // K argument for TX_DETAIL int32 txDetail_m; // M argument for TX_DETAIL int32 txDetail_n; // N argument for TX_DETAIL int32 txDetail_s; // Scramble argument for TX_DETAIL int32 useTile; // TRUE if using next for floats for TX_TILE float32 txTile_ll_u; // Lower-left u value for TX_TILE float32 txTile_ll_v; // Lower-left v value for TX_TILE float32 txTile_ur_u; // Upper-right u value for TX_TILE float32 txTile_ur_v; // Upper-right v value for TX_TILE int32 projection; // Projection // 0 = Flat earth // 3 = Lambert conic // 4 = UTM // 7 = Undefined projection int32 earthModel; // Earth model // 0 = WGS84 // 1 = WGS72 // 2 = Bessel // 3 = Clark 1866 // 4 = NAD27 // int32 reserved4; // Reserved int32 utmZone; // UTM zone int32 imageOrigin; // Image origin // 0 = Lower-left // 1 = Upper-left int32 geoUnits; // Geospecific points units // 0 = Degrees // 1 = Meters // 2 = Pixels // int32 reserved5; // Reserved // int32 reserved6; // Reserved int32 hemisphere; // Hemisphere for geospecific points units // 0 = Southern // 1 = Northern // int32 reserved7; // Reserved // int32 reserved8; // Reserved // int32 spare3[149]; // Spare // char comments[512]; // Comments std::string comments; // -------------- // v12 ends here // -------------- // int32 reserved9[13]; // Reserved int32 attrVersion; // Attribute file version number int32 controlPoints; // Number of geospecific control points // If the number of geospecific control points is > 0, // the following fields are also in the attribute file: int32 reserved10; // Reserved #if 0 // For each geospecific control point: { float64 texel_u; // Texel u of geospecific control point float64 texel_v; // Texel v of geospecific control point float64 geoPoint[2]; // Real earth coordinate of geospecific control point // (this value depends on the projection, earth model, // and geospecific points units) } // ---------------- // v15.6 ends here // ---------------- // After all geospecific control points are listed, the following subtexture // information appears: int32 subtextures; // Number of subtexture definitions contained in the // texture attribute file // If the number of subtexture definitions is >0, // the following fields are repeated for each subtexture definition: { char name[32]; // name of subtexture definition int32 left; // Coordinate of left edge of subtexture // definition measured in texels. int32 bottom; // Coordinate of bottom edge of subtexture // definition measured in texels. int32 right; // Coordinate of right edge of subtexture // definition measured in texels. int32 top; // Coordinate of top edge of subtexture // definition measured in texels. } #endif int32 numSubtextures; // # of subtextures }; } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/PaletteRecords.cpp0000644000175000017500000007141013151044751027471 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight (R) loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include #include #include #include #include "Registry.h" #include "Document.h" #include "AttrData.h" #include "RecordInputStream.h" #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) #define GL_RGB5 0x8050 #define GL_RGBA4 0x8056 #define GL_RGBA8 0x8058 #define GL_RGBA12 0x805A #define GL_RGB12 0x8053 #define GL_LUMINANCE12_ALPHA4 0x8046 #define GL_LUMINANCE12_ALPHA12 0x8047 #define GL_INTENSITY16 0x804D #endif #if defined(OSG_GL3_AVAILABLE) #define GL_LUMINANCE12_ALPHA4 0x8046 #define GL_LUMINANCE12_ALPHA12 0x8047 #define GL_INTENSITY16 0x804D #endif namespace flt { class VertexPalette : public Record { public: VertexPalette() {} META_Record(VertexPalette) protected: virtual ~VertexPalette() {} virtual void readRecord(RecordInputStream& in, Document& document) { uint32 paletteSize = in.readUInt32(); // Entries in vertex pool found by offset from start of this record. const uint32 RECORD_HEADER_SIZE = 4; const uint32 OFFSET = RECORD_HEADER_SIZE+sizeof(paletteSize); std::string buffer(paletteSize,'\0'); if (OFFSET < paletteSize) { in.read(&buffer[OFFSET], paletteSize-OFFSET); } // Keep a copy of the vertex pool in memory for later reference. document.setVertexPool(new VertexPool(buffer)); } }; REGISTER_FLTRECORD(VertexPalette, VERTEX_PALETTE_OP) class ColorPalette : public Record { public: ColorPalette() {} META_Record(ColorPalette) protected: virtual ~ColorPalette() {} virtual void readRecord(RecordInputStream& in, Document& document) { if (document.getColorPoolParent()) // Using parent's color pool -- ignore this record. return; if (document.version() > VERSION_13) { bool oldVersion = false; bool colorNameSection = in.getRecordSize() > 4228; int maxColors = (document.version()>=VERSION_15_1) ? 1024 : 512; // It might be less. if (!colorNameSection) { // Max colors calculated by record size. int maxColorsByRecordSize = (in.getRecordBodySize()-128) / 4; if (maxColorsByRecordSize < maxColors) maxColors = maxColorsByRecordSize; } ColorPool* cp = new ColorPool(oldVersion,maxColors); document.setColorPool(cp); in.forward(128); for (int i=0; isetName(name); material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(ambient,alpha)); material->setDiffuse (osg::Material::FRONT_AND_BACK,osg::Vec4(diffuse,alpha)); material->setSpecular(osg::Material::FRONT_AND_BACK,osg::Vec4(specular,alpha)); material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(emissive,alpha)); if (shininess>=0.0f) { material->setShininess(osg::Material::FRONT_AND_BACK,shininess); } else { OSG_INFO<<"Warning: OpenFlight shininess value out of range: "<setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(ambient,alpha)); material->setDiffuse (osg::Material::FRONT_AND_BACK,osg::Vec4(diffuse,alpha)); material->setSpecular(osg::Material::FRONT_AND_BACK,osg::Vec4(specular,alpha)); material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(emissive,alpha)); if (shininess>=0.0f) { material->setShininess(osg::Material::FRONT_AND_BACK,shininess); } else { OSG_INFO<<"Warning: OpenFlight shininess value out of range: "< image = osgDB::readRefImageFile(filename,document.getOptions()); if (!image) return NULL; // Create stateset to hold texture and attributes. osg::StateSet* stateset = new osg::StateSet; osg::Texture2D* texture = new osg::Texture2D; texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT); texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT); texture->setResizeNonPowerOfTwoHint(true); texture->setImage(image.get()); stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); // Read attribute file std::string attrname = filename + ".attr"; osg::ref_ptr attr = osgDB::readRefFile(attrname,document.getOptions()); if (attr.valid()) { // Wrap mode osg::Texture2D::WrapMode wrap_s = convertWrapMode(attr->wrapMode_u,document); texture->setWrap(osg::Texture2D::WRAP_S,wrap_s); osg::Texture2D::WrapMode wrap_t = convertWrapMode(attr->wrapMode_v,document); texture->setWrap(osg::Texture2D::WRAP_T,wrap_t); // Min filter switch (attr->minFilterMode) { case AttrData::MIN_FILTER_POINT: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST); break; case AttrData::MIN_FILTER_BILINEAR: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); break; case AttrData::MIN_FILTER_MIPMAP_POINT: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST_MIPMAP_NEAREST); break; case AttrData::MIN_FILTER_MIPMAP_LINEAR: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST_MIPMAP_LINEAR); break; case AttrData::MIN_FILTER_MIPMAP_BILINEAR: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_NEAREST); break; case AttrData::MIN_FILTER_MIPMAP_TRILINEAR: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_LINEAR); break; case AttrData::MIN_FILTER_BICUBIC: case AttrData::MIN_FILTER_BILINEAR_GEQUAL: case AttrData::MIN_FILTER_BILINEAR_LEQUAL: case AttrData::MIN_FILTER_BICUBIC_GEQUAL: case AttrData::MIN_FILTER_BICUBIC_LEQUAL: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_NEAREST); break; default: texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_LINEAR); break; } // Mag filter switch (attr->magFilterMode) { case AttrData::MAG_FILTER_POINT: texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST); break; case AttrData::MAG_FILTER_BILINEAR: case AttrData::MAG_FILTER_BILINEAR_GEQUAL: case AttrData::MAG_FILTER_BILINEAR_LEQUAL: case AttrData::MAG_FILTER_SHARPEN: case AttrData::MAG_FILTER_BICUBIC: case AttrData::MAG_FILTER_BICUBIC_GEQUAL: case AttrData::MAG_FILTER_BICUBIC_LEQUAL: case AttrData::MAG_FILTER_ADD_DETAIL: case AttrData::MAG_FILTER_MODULATE_DETAIL: texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); break; } // Internal mode switch(attr->intFormat) { case AttrData::INTERNAL_FORMAT_TX_I_12A_4: texture->setInternalFormat(GL_LUMINANCE12_ALPHA4); break; case AttrData::INTERNAL_FORMAT_TX_IA_8: texture->setInternalFormat(GL_LUMINANCE_ALPHA); break; case AttrData::INTERNAL_FORMAT_TX_RGB_5: texture->setInternalFormat(GL_RGB5); break; case AttrData::INTERNAL_FORMAT_TX_RGBA_4: texture->setInternalFormat(GL_RGBA4); break; case AttrData::INTERNAL_FORMAT_TX_IA_12: texture->setInternalFormat(GL_LUMINANCE12_ALPHA12); break; case AttrData::INTERNAL_FORMAT_TX_RGBA_8: texture->setInternalFormat(GL_RGBA8); break; case AttrData::INTERNAL_FORMAT_TX_RGBA_12: texture->setInternalFormat(GL_RGBA12); break; case AttrData::INTERNAL_FORMAT_TX_I_16: texture->setInternalFormat(GL_INTENSITY16); break; case AttrData::INTERNAL_FORMAT_TX_RGB_12: texture->setInternalFormat(GL_RGB12); break; case AttrData::INTERNAL_FORMAT_DEFAULT: default: // Do nothing, just use the image data format break; } osg::TexEnv* texenv = new osg::TexEnv; switch (attr->texEnvMode) { case AttrData::TEXENV_MODULATE: texenv->setMode(osg::TexEnv::MODULATE); break; case AttrData::TEXENV_BLEND: texenv->setMode(osg::TexEnv::BLEND); break; case AttrData::TEXENV_DECAL: texenv->setMode(osg::TexEnv::DECAL); break; case AttrData::TEXENV_COLOR: texenv->setMode(osg::TexEnv::REPLACE); break; case AttrData::TEXENV_ADD: texenv->setMode(osg::TexEnv::ADD); break; } stateset->setTextureAttribute(0, texenv); } return stateset; } virtual void readRecord(RecordInputStream& in, Document& document) { if (document.getTexturePoolParent()) // Using parent's texture pool -- ignore this record. return; int maxLength = (document.version() < VERSION_14) ? 80 : 200; std::string filename = in.readString(maxLength); int32 index = in.readInt32(-1); /*int32 x =*/ in.readInt32(); /*int32 y =*/ in.readInt32(); // Need full path for unique key in local texture cache. std::string pathname = osgDB::findDataFile(filename,document.getOptions()); if (pathname.empty()) { OSG_WARN << "Can't find texture (" << index << ") " << filename << std::endl; return; } // Is texture in local cache? osg::StateSet* stateset = flt::Registry::instance()->getTextureFromLocalCache(pathname); // Read file if not in cache. if (!stateset) { stateset = readTexture(pathname,document); // Add to texture cache. flt::Registry::instance()->addTextureToLocalCache(pathname,stateset); } // Add to texture pool. TexturePool* tp = document.getOrCreateTexturePool(); (*tp)[index] = stateset; } }; REGISTER_FLTRECORD(TexturePalette, TEXTURE_PALETTE_OP) class EyepointAndTrackplanePalette : public Record { public: EyepointAndTrackplanePalette() {} META_Record(EyepointAndTrackplanePalette) protected: virtual ~EyepointAndTrackplanePalette() {} virtual void readRecord(RecordInputStream& /*in*/, Document& /*document*/) {} }; REGISTER_FLTRECORD(EyepointAndTrackplanePalette, EYEPOINT_AND_TRACKPLANE_PALETTE_OP) class LinkagePalette : public Record { public: LinkagePalette() {} META_Record(LinkagePalette) protected: virtual ~LinkagePalette() {} virtual void readRecord(RecordInputStream& /*in*/, Document& /*document*/) {} }; REGISTER_FLTRECORD(LinkagePalette, LINKAGE_PALETTE_OP) class SoundPalette : public Record { public: SoundPalette() {} META_Record(SoundPalette) protected: virtual ~SoundPalette() {} virtual void readRecord(RecordInputStream& /*in*/, Document& /*document*/) {} }; REGISTER_FLTRECORD(SoundPalette, SOUND_PALETTE_OP) class LightSourcePalette : public Record { public: LightSourcePalette() {} META_Record(LightSourcePalette) enum LightType { INFINITE_LIGHT = 0, LOCAL_LIGHT = 1, SPOT_LIGHT = 2 }; protected: virtual ~LightSourcePalette() {} virtual void readRecord(RecordInputStream& in, Document& document) { if (document.getLightSourcePoolParent()) // Using parent's texture pool -- ignore this record. return; int32 index = in.readInt32(-1); in.forward(2*4); std::string name = in.readString(20); in.forward(4); osg::Vec4f ambient = in.readVec4f(); osg::Vec4f diffuse = in.readVec4f(); osg::Vec4f specular = in.readVec4f(); int32 type = in.readInt32(); in.forward(4*10); float32 spotExponent = in.readFloat32(); float32 spotCutoff = in.readFloat32(); /*float32 yaw =*/ in.readFloat32(); /*float32 pitch =*/ in.readFloat32(); float32 constantAttenuation = in.readFloat32(); float32 linearAttenuation = in.readFloat32(); float32 quadraticAttenuation = in.readFloat32(); /*int32 active =*/ in.readInt32(); osg::ref_ptr light = new osg::Light; light->setAmbient(ambient); light->setDiffuse(diffuse); light->setSpecular(specular); switch (type) { case INFINITE_LIGHT: light->setPosition(osg::Vec4(0.0f,0.0f,1.0f,0.0f)); break; case LOCAL_LIGHT: light->setPosition(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); light->setConstantAttenuation(constantAttenuation); light->setLinearAttenuation(linearAttenuation); light->setQuadraticAttenuation(quadraticAttenuation); break; case SPOT_LIGHT: light->setPosition(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); light->setDirection(osg::Vec3(0.0f,1.0f,0.0f)); light->setConstantAttenuation(constantAttenuation); light->setLinearAttenuation(linearAttenuation); light->setQuadraticAttenuation(quadraticAttenuation); light->setSpotExponent(spotExponent); light->setSpotCutoff(spotCutoff); break; } // Add to pool LightSourcePool* pool = document.getOrCreateLightSourcePool(); (*pool)[index] = light.get(); } }; REGISTER_FLTRECORD(LightSourcePalette, LIGHT_SOURCE_PALETTE_OP) class LightPointAppearancePalette : public Record { public: LightPointAppearancePalette() {} META_Record(LightPointAppearancePalette) protected: virtual ~LightPointAppearancePalette() {} virtual void readRecord(RecordInputStream& in, Document& document) { if (document.getLightPointAppearancePoolParent()) // Using parent's light point appearance pool -- ignore this record. return; osg::ref_ptr appearance = new LPAppearance; in.forward(4); appearance->name = in.readString(256); appearance->index = in.readInt32(-1); appearance->materialCode = in.readInt16(); appearance->featureID = in.readInt16(); int32 backColorIndex = in.readInt32(); appearance->backColor = document.getColorPool() ? document.getColorPool()->getColor(backColorIndex) : osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f); appearance->displayMode = in.readInt32(); appearance->intensityFront = in.readFloat32(); appearance->intensityBack = in.readFloat32(); appearance->minDefocus = in.readFloat32(); appearance->maxDefocus = in.readFloat32(); appearance->fadingMode = in.readInt32(); appearance->fogPunchMode = in.readInt32(); appearance->directionalMode = in.readInt32(); appearance->rangeMode = in.readInt32(); appearance->minPixelSize = in.readFloat32(); appearance->maxPixelSize = in.readFloat32(); appearance->actualPixelSize = in.readFloat32(); appearance->transparentFalloffPixelSize = in.readFloat32(); appearance->transparentFalloffExponent = in.readFloat32(); appearance->transparentFalloffScalar = in.readFloat32(); appearance->transparentFalloffClamp = in.readFloat32(); appearance->fogScalar = in.readFloat32(); appearance->fogIntensity = in.readFloat32(); appearance->sizeDifferenceThreshold = in.readFloat32(); appearance->directionality = in.readInt32(); appearance->horizontalLobeAngle = in.readFloat32(); appearance->verticalLobeAngle = in.readFloat32(); appearance->lobeRollAngle = in.readFloat32(); appearance->directionalFalloffExponent = in.readFloat32(); appearance->directionalAmbientIntensity = in.readFloat32(); appearance->significance = in.readFloat32(); appearance->flags = in.readUInt32(); appearance->visibilityRange = in.readFloat32(); appearance->fadeRangeRatio = in.readFloat32(); appearance->fadeInDuration = in.readFloat32(); appearance->fadeOutDuration = in.readFloat32(); appearance->LODRangeRatio = in.readFloat32(); appearance->LODScale = in.readFloat32(); if(document.version() > VERSION_15_8) appearance->texturePatternIndex = in.readInt16(-1); else appearance->texturePatternIndex = -1; // The final short is reserved; don't bother reading it. // Add to pool LightPointAppearancePool* lpaPool = document.getOrCreateLightPointAppearancePool(); (*lpaPool)[appearance->index] = appearance.get(); } }; REGISTER_FLTRECORD(LightPointAppearancePalette, LIGHT_POINT_APPEARANCE_PALETTE_OP) class LightPointAnimationPalette : public Record { public: LightPointAnimationPalette() {} META_Record(LightPointAnimationPalette) protected: virtual ~LightPointAnimationPalette() {} virtual void readRecord(RecordInputStream& in, Document& document) { if (document.getLightPointAnimationPoolParent()) // Using parent's light point animation pool -- ignore this record. return; osg::ref_ptr animation = new LPAnimation; in.forward(4); animation->name = in.readString(256); animation->index = in.readInt32(-1); // Rotating or strobe animation->animationPeriod = in.readFloat32(); animation->animationPhaseDelay = in.readFloat32(); animation->animationEnabledPeriod = in.readFloat32(); animation->axisOfRotation = in.readVec3f(); animation->flags = in.readUInt32(); animation->animationType = in.readInt32(); // Morse code animation->morseCodeTiming = in.readInt32(); animation->wordRate = in.readInt32(); animation->characterRate = in.readInt32(); animation->morseCodeString = in.readString(1024); // Flashing sequence int32 numberOfSequences = in.readInt32(); for (int n=0; nsequence.push_back(pulse); } // Add to pool LightPointAnimationPool* lpaPool = document.getOrCreateLightPointAnimationPool(); (*lpaPool)[animation->index] = animation.get(); } }; REGISTER_FLTRECORD(LightPointAnimationPalette, LIGHT_POINT_ANIMATION_PALETTE_OP) class LineStylePalette : public Record { public: LineStylePalette() {} META_Record(LineStylePalette) protected: virtual ~LineStylePalette() {} virtual void readRecord(RecordInputStream& /*in*/, Document& /*document*/) { } }; REGISTER_FLTRECORD(LineStylePalette, LINE_STYLE_PALETTE_OP) class TextureMappingPalette : public Record { public: TextureMappingPalette() {} META_Record(TextureMappingPalette) protected: virtual ~TextureMappingPalette() {} virtual void readRecord(RecordInputStream& /*in*/, Document& /*document*/) { } }; REGISTER_FLTRECORD(TextureMappingPalette, TEXTURE_MAPPING_PALETTE_OP) class ShaderPalette : public Record { public: ShaderPalette() {} META_Record(ShaderPalette) enum ShaderType { CG=0, CGFX=1, GLSL=2 }; protected: virtual ~ShaderPalette() {} virtual void readRecord(RecordInputStream& in, Document& document) { if (document.getShaderPoolParent()) // Using parent's shader pool -- ignore this record. return; int32 index = in.readInt32(-1); int32 type = in.readInt32(-1); std::string name = in.readString(1024); if (type == CG) { // CG support is currently not implemented. Just parse. std::string vertexProgramFilename = in.readString(1024); std::string fragmentProgramFilename = in.readString(1024); /*int32 vertexProgramProfile =*/ in.readInt32(); /*int32 fragmentProgramProfile =*/ in.readInt32(); std::string vertexProgramEntry = in.readString(256); std::string fragmentProgramEntry = in.readString(256); } else if (type == GLSL) { int32 vertexProgramFileCount(1); int32 fragmentProgramFileCount(1); if (document.version() >= VERSION_16_1) { // In 16.1, possibly multiple filenames for each vertex and fragment program. vertexProgramFileCount = in.readInt32(); fragmentProgramFileCount = in.readInt32(); } // else 16.0 // Technically, 16.0 didn't support GLSL, but this plugin // supports it with a single vertex shader filename and a // single fragment shader filename. osg::Program* program = new osg::Program; program->setName(name); // Read vertex programs int idx; for( idx=0; idx vertexShader = osgDB::readRefShaderFile(osg::Shader::VERTEX, vertexProgramFilePath); if (vertexShader) program->addShader( vertexShader ); } } // Read fragment programs for( idx=0; idx fragmentShader = osgDB::readRefShaderFile(osg::Shader::FRAGMENT, fragmentProgramFilePath); if (fragmentShader) program->addShader( fragmentShader ); } } // Add to shader pool ShaderPool* shaderPool = document.getOrCreateShaderPool(); (*shaderPool)[index] = program; } } }; REGISTER_FLTRECORD(ShaderPalette, SHADER_PALETTE_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/GeometryRecords.cpp0000644000175000017500000013462613151044751027677 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include #include #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" #include #include namespace flt { template void reverseWindingOrder( ARRAY* data, GLenum mode, GLint first, GLint last ) { switch( mode ) { case osg::PrimitiveSet::TRIANGLES: case osg::PrimitiveSet::QUADS: case osg::PrimitiveSet::POLYGON: // reverse all the vertices. std::reverse(data->begin()+first, data->begin()+last); break; case osg::PrimitiveSet::TRIANGLE_STRIP: case osg::PrimitiveSet::QUAD_STRIP: // reverse only the shared edges. for( GLint i = first; i < last-1; i+=2 ) { std::swap( (*data)[i], (*data)[i+1] ); } break; case osg::PrimitiveSet::TRIANGLE_FAN: // reverse all vertices except the first vertex. std::reverse(data->begin()+first+1, data->begin()+last); break; } } void addDrawableAndReverseWindingOrder( osg::Geode* geode ) { // Replace double sided polygons by duplicating the drawables and inverting the normals. std::vector new_drawables; for (size_t i=0; igetNumDrawables(); ++i) { const osg::Geometry* geometry = dynamic_cast(geode->getDrawable(i)); if(geometry) { osg::Geometry* geom = new osg::Geometry(*geometry , osg::CopyOp::DEEP_COPY_ARRAYS | osg::CopyOp::DEEP_COPY_PRIMITIVES); new_drawables.push_back(geom); for( size_t i = 0; i < geom->getNumPrimitiveSets( ); ++i ) { osg::DrawArrays* drawarray = dynamic_cast( geom->getPrimitiveSet( i ) ); if( drawarray ) { GLint first = drawarray->getFirst(); GLint last = drawarray->getFirst()+drawarray->getCount(); // Invert vertex order. osg::Vec3Array* vertices = dynamic_cast(geom->getVertexArray()); if( vertices ) { reverseWindingOrder( vertices, drawarray->getMode(), first, last ); } if( osg::getBinding(geom->getNormalArray()) == osg::Array::BIND_PER_VERTEX ) { osg::Vec3Array* normals = dynamic_cast(geom->getNormalArray()); if( normals ) { // First, invert the direction of the normals. for( GLint i = first; i < last; ++i ) { (*normals)[i] = -(*normals)[i]; } reverseWindingOrder( normals, drawarray->getMode(), first, last ); } } if( osg::getBinding(geom->getColorArray()) == osg::Array::BIND_PER_VERTEX ) { osg::Vec4Array* colors = dynamic_cast(geom->getColorArray()); if( colors ) { reverseWindingOrder( colors, drawarray->getMode(), first, last ); } } for( size_t i = 0; i < geom->getNumTexCoordArrays(); ++i ) { osg::Vec2Array* UVs = dynamic_cast(geom->getTexCoordArray(i)); if( UVs ) { reverseWindingOrder( UVs, drawarray->getMode(), first, last ); } } } } } } // Now add the new geometry drawable. for( size_t i = 0; i < new_drawables.size( ); ++i ) { geode->addDrawable( new_drawables[i] ); } } /* Face record */ class Face : public PrimaryRecord { // flags static const unsigned int TERRAIN_BIT = 0x80000000u >> 0; static const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; static const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout static const unsigned int HIDDEN_BIT = 0x80000000u >> 5; static const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; osg::Vec4 _primaryColor; uint8 _drawFlag; uint8 _template; uint16 _transparency; uint32 _flags; uint8 _lightMode; osg::ref_ptr _geode; osg::ref_ptr _geometry; public: Face() : _primaryColor(1,1,1,1), _drawFlag(SOLID_NO_BACKFACE), _template(FIXED_NO_ALPHA_BLENDING), _transparency(0), _flags(0), _lightMode(FACE_COLOR) { } META_Record(Face) META_setID(_geode) META_setComment(_geode) META_setMultitexture(_geode) // draw mode enum DrawMode { SOLID_BACKFACED = 0, SOLID_NO_BACKFACE = 1, WIREFRAME_CLOSED = 2, WIREFRAME_NOT_CLOSED = 3, SURROUND_ALTERNATE_COLOR = 4, OMNIDIRECTIONAL_LIGHT = 8, UNIDIRECTIONAL_LIGHT = 9, BIDIRECTIONAL_LIGHT = 10 }; inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; } // lighting enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; inline LightMode getLightMode() const { return (LightMode)_lightMode; } inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); } inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); } // flags inline bool noColor() const { return (_flags & NO_COLOR_BIT)!=0; } inline bool isHidden() const { return (_flags & HIDDEN_BIT)!=0; } inline bool isTerrain() const { return (_flags & TERRAIN_BIT)!=0; } inline bool isFootprint() const { return (_flags & FOOTPRINT_BIT)!=0; } inline bool isRoofline() const { return (_flags & ROOFLINE_BIT)!=0; } inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; } // billboard enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; } // transparency & alpha inline bool isAlphaBlend() const { return (_template==FIXED_ALPHA_BLENDING) || (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) || (_template==POINT_ROTATE_WITH_ALPHA_BLENDING); } inline osg::Vec4 getPrimaryColor() const { return _primaryColor; } inline float getTransparency() const { return (float)_transparency / 65535.0f; } inline bool isTransparent() const { return _transparency > 0; } virtual void addChild(osg::Node& child) { // Add subface to parent. if (_parent.valid()) _parent->addChild(child); } virtual void addVertex(Vertex& vertex) { osg::Vec3Array* vertices = getOrCreateVertexArray(*_geometry); vertices->push_back(vertex._coord); if (isGouraud()) { osg::Vec4Array* colors = getOrCreateColorArray(*_geometry); if (vertex.validColor()) { colors->push_back(vertex._color); } else { // Use face color if vertex color is -1 in a gouraud polygon. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000967.html // Incorporate Face transparency per osg-users thread "Open Flight // characteristic not reflected in the current OSG" (Sept/Oct 2011) colors->push_back(osg::Vec4(_primaryColor.r(), _primaryColor.g(), _primaryColor.b(), ( 1.0 - getTransparency() ) )); } } bool strict = false; // prepare for "strict" reader option. if (strict) { if (vertex.validNormal()) { osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry); normals->push_back(vertex._normal); } } else { // Add normal only if lit. if (isLit()) { osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry); if (vertex.validNormal()) normals->push_back(vertex._normal); else // if lit and no normal in Vertex { // Use previous normal if available. if (normals->empty()) normals->push_back(osg::Vec3(0,0,1)); else normals->push_back(normals->back()); } } } for (int layer=0; layerpush_back(vertex._uv[layer]); } } } virtual void addVertexUV(int unit, const osg::Vec2& uv) { osg::Vec2Array* UVs = getOrCreateTextureArray(*_geometry,unit); UVs->push_back(uv); } virtual void addMorphVertex(Vertex& vertex0, Vertex& /*vertex100*/) { osg::Vec3Array* vertices = getOrCreateVertexArray(*_geometry); vertices->push_back(vertex0._coord); if (isGouraud()) { osg::Vec4Array* colors = getOrCreateColorArray(*_geometry); if (vertex0.validColor()) { colors->push_back(vertex0._color); } else { // Use face color if vertex color is -1 in a gouraud polygon. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000967.html colors->push_back(_primaryColor); } } if (vertex0.validNormal()) { osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry); normals->push_back(vertex0._normal); } for (int layer=0; layerpush_back(vertex0._uv[layer]); } } } protected: virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); int32 IRColor = in.readInt32(); /*int16 relativePriority =*/ in.readInt16(); _drawFlag = in.readUInt8(SOLID_NO_BACKFACE); uint8 texturedWhite = in.readUInt8(); int16 primaryNameIndex = in.readInt16(-1); /*int16 secondaryNameIndex =*/ in.readInt16(-1); in.forward(1); _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING); /*int detailTexture =*/ in.readInt16(-1); int textureIndex = in.readInt16(-1); int materialIndex = in.readInt16(-1); int16 surface = in.readInt16(); int16 feature = in.readInt16(); int32 IRMaterial = in.readInt32(); _transparency = in.readUInt16(0); // version > 13 /*uint8 influenceLOD =*/ in.readUInt8(); /*uint8 linestyle =*/ in.readUInt8(); _flags = in.readUInt32(0); _lightMode = in.readUInt8(FACE_COLOR); in.forward(7); osg::Vec4 primaryPackedColor = in.readColor32(); /*osg::Vec4 secondaryPackedColor =*/ in.readColor32(); // version >= VERSION_15_1 /*int textureMappingIndex =*/ in.readInt16(-1); in.forward(2); int primaryColorIndex = in.readInt32(-1); /*int alternateColorIndex =*/ in.readInt32(-1); // version >= 16 in.forward(2); int shaderIndex = in.readInt16(-1); // Create Geode or Billboard. switch (_template) { case AXIAL_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::AXIAL_ROT); _geode = billboard; } break; case POINT_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::POINT_ROT_WORLD); _geode = billboard; } break; default: _geode = new osg::Geode; } _geode->setDataVariance(osg::Object::STATIC); _geode->setName(id); _geometry = new osg::Geometry; _geometry->setDataVariance(osg::Object::STATIC); _geode->addDrawable(_geometry.get()); // StateSet osg::ref_ptr stateset = new osg::StateSet; // Hidden if (isHidden()) _geode->setNodeMask(0); // Face color if (texturedWhite!=0 && textureIndex>=0) { _primaryColor = osg::Vec4(1,1,1,1); } else { if (packedColorMode()) { _primaryColor = primaryPackedColor; } else { if (document.version() < VERSION_15_1) _primaryColor = document.getColorPool()->getColor(primaryNameIndex); else // >= VERSION_15_1 _primaryColor = document.getColorPool()->getColor(primaryColorIndex); } } // Lighting stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF); // Material if (isLit() || materialIndex>=0) { // MaterialPool will return a "default" material if no material is defined for materialIndex. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html osg::Vec4 col = _primaryColor; col.a() = 1.0f - getTransparency(); osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col); stateset->setAttribute(material); } // IRColor (IRC) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != IRColor) { _geometry->setUserValue("", IRColor); } // IR Material ID (IRM) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != IRMaterial) { _geometry->setUserValue("", IRMaterial); } // surface (SMC) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != surface) { _geometry->setUserValue("", surface); } // feature (FID) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != feature) { _geometry->setUserValue("", feature); } // Shaders if (shaderIndex >= 0) { ShaderPool* sp = document.getOrCreateShaderPool(); osg::Program* program = sp->get(shaderIndex); if (program) stateset->setAttributeAndModes(program, osg::StateAttribute::ON); } // Texture TexturePool* tp = document.getOrCreateTexturePool(); osg::StateSet* textureStateSet = tp->get(textureIndex); if (textureStateSet) { // Merge face stateset with texture stateset stateset->merge(*textureStateSet); } // Cull face switch(_drawFlag) { case SOLID_BACKFACED: // Enable backface culling { static osg::ref_ptr cullFace = new osg::CullFace(osg::CullFace::BACK); stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); break; } case SOLID_NO_BACKFACE: // Disable backface culling if( document.getReplaceDoubleSidedPolys( ) ) { static osg::ref_ptr cullFace = new osg::CullFace(osg::CullFace::BACK); stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); } else { stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); } break; } // Subface if (document.subfaceLevel() > 0) { stateset->setAttributeAndModes(document.getSubSurfacePolygonOffset(document.subfaceLevel()), osg::StateAttribute::ON); stateset->setAttribute(document.getSubSurfaceDepth()); stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin"); } _geode->setStateSet(stateset.get()); // Add to parent. if (_parent.valid()) _parent->addChild(*_geode); } osg::PrimitiveSet::Mode getPrimitiveSetMode(int numVertices) { switch(getDrawMode()) { case WIREFRAME_NOT_CLOSED: return osg::PrimitiveSet::LINE_STRIP; case WIREFRAME_CLOSED: return osg::PrimitiveSet::LINE_LOOP; case OMNIDIRECTIONAL_LIGHT: case UNIDIRECTIONAL_LIGHT: case BIDIRECTIONAL_LIGHT: return osg::PrimitiveSet::POINTS; default: break; } switch (numVertices) { case 1: return osg::PrimitiveSet::POINTS; case 2: return osg::PrimitiveSet::LINES; case 3: return osg::PrimitiveSet::TRIANGLES; case 4: return osg::PrimitiveSet::QUADS; default: break; } return osg::PrimitiveSet::POLYGON; } virtual void dispose(Document& document) { if (_geode.valid()) { // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_geode,*_matrix,_numberOfReplications); } // Add primitives, set bindings etc. for (unsigned int i=0; i<_geode->getNumDrawables(); ++i) { osg::Geometry* geometry = dynamic_cast(_geode->getDrawable(i)); if (geometry) { osg::Array* vertices = geometry->getVertexArray(); if (vertices) { GLint first = 0; GLsizei count = vertices->getNumElements(); osg::PrimitiveSet::Mode mode = getPrimitiveSetMode(count); geometry->addPrimitiveSet(new osg::DrawArrays(mode,first,count)); } // Color binding if (isGouraud()) { // Color per vertex if (geometry->getColorArray()) geometry->getColorArray()->setBinding(osg::Array::BIND_PER_VERTEX); } else { // Color per face osg::Vec4 col = getPrimaryColor(); col[3] = 1.0f - getTransparency(); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0] = col; geometry->setColorArray(colors, osg::Array::BIND_OVERALL); } // Normal binding if (isLit()) { if (geometry->getNormalArray()) geometry->getNormalArray()->setBinding(osg::Array::BIND_PER_VERTEX); } else { geometry->setNormalArray(0); } } } if( getDrawMode( ) == SOLID_NO_BACKFACE && document.getReplaceDoubleSidedPolys( ) ) { addDrawableAndReverseWindingOrder( _geode.get() ); } osg::StateSet* stateset = _geode->getOrCreateStateSet(); // Translucent image? bool isImageTranslucent = false; if (document.getUseTextureAlphaForTransparancyBinning()) { for (unsigned int i=0; igetTextureAttributeList().size(); ++i) { osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE); osg::Texture2D* texture = dynamic_cast(sa); if (texture) { osg::Image* image = texture->getImage(); if (image && image->isImageTranslucent()) isImageTranslucent = true; } } } // Transparent Material? bool isMaterialTransparent = false; osg::Material* material = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (material) { isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f; } // Enable alpha blend? if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent) { static osg::ref_ptr blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } if (document.getUseBillboardCenter()) { // Set billboard rotation point to center of face. osg::Billboard* billboard = dynamic_cast(_geode.get()); if (billboard) { for (unsigned int i=0; igetNumDrawables(); ++i) { const osg::BoundingBox& bb = billboard->getDrawable(i)->getBoundingBox(); billboard->setPosition(i,bb.center()); osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center())); billboard->getDrawable(i)->accept(tf); billboard->getDrawable(i)->dirtyBound(); } billboard->dirtyBound(); } } } } }; REGISTER_FLTRECORD(Face, FACE_OP) /** VertexList - * The VertexList is a leaf record. * Possible parents: Face, Mesh & LightPoint */ class VertexListRecord : public PrimaryRecord { public: VertexListRecord() {} META_Record(VertexListRecord) virtual void addVertex(Vertex& vertex) { // forward vertex to parent. if (_parent.valid()) _parent->addVertex(vertex); } virtual void addVertexUV(int layer,const osg::Vec2& uv) { // forward uv to parent. if (_parent.valid()) _parent->addVertexUV(layer,uv); } protected: virtual ~VertexListRecord() {} virtual void readRecord(RecordInputStream& in, Document& document) { VertexPool* vp = document.getVertexPool(); if (vp) { int vertices = (in.getRecordSize()-4) / 4; // Use the Vertex pool as a record stream. RecordInputStream inVP(vp->rdbuf()); for (int n=0; naddMorphVertex(_vertex0, _vertex100); break; case UNDEFINED: break; } } //virtual void addVertexUV(int layer,const osg::Vec2& uv) //{ // // forward uv to parent. // if (_parent.valid()) // _parent->addVertexUV(layer,uv); //} protected: virtual ~MorphVertexList() {} virtual void readRecord(RecordInputStream& in, Document& document) { VertexPool* vp = document.getVertexPool(); if (vp) { int vertices = (in.getRecordSize()-4) / 8; // Use the Vertex pool as a record stream. RecordInputStream inVP(vp->rdbuf()); for (int n=0; n> 0; static const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; static const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout static const unsigned int HIDDEN_BIT = 0x80000000u >> 5; static const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; osg::Vec4 _primaryColor; uint8 _drawFlag; uint8 _template; uint16 _transparency; uint32 _flags; uint8 _lightMode; osg::ref_ptr _geode; public: Mesh() : _primaryColor(1,1,1,1), _drawFlag(SOLID_NO_BACKFACE), _template(FIXED_NO_ALPHA_BLENDING), _transparency(0), _flags(0), _lightMode(FACE_COLOR) { } META_Record(Mesh) META_setID(_geode) META_setComment(_geode) META_setMultitexture(_geode) // draw mode enum DrawMode { SOLID_BACKFACED = 0, SOLID_NO_BACKFACE = 1, WIREFRAME_CLOSED = 2, WIREFRAME_NOT_CLOSED = 3, SURROUND_ALTERNATE_COLOR = 4, OMNIDIRECTIONAL_LIGHT = 8, UNIDIRECTIONAL_LIGHT = 9, BIDIRECTIONAL_LIGHT = 10 }; inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; } // lighting enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; inline LightMode getLightMode() const { return (LightMode)_lightMode; } inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); } inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); } // flags inline bool noColor() const { return (_flags & NO_COLOR_BIT)!=0; } inline bool isHidden() const { return (_flags & HIDDEN_BIT)!=0; } inline bool isTerrain() const { return (_flags & TERRAIN_BIT)!=0; } inline bool isFootprint() const { return (_flags & FOOTPRINT_BIT)!=0; } inline bool isRoofline() const { return (_flags & ROOFLINE_BIT)!=0; } inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; } // billboard enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; } // transparency & alpha inline bool isAlphaBlend() const { return (_template==FIXED_ALPHA_BLENDING) || (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) || (_template==POINT_ROTATE_WITH_ALPHA_BLENDING); } inline osg::Vec4 getPrimaryColor() const { return _primaryColor; } inline float getTransparency() const { return (float)_transparency / 65535.0f; } inline bool isTransparent() const { return _transparency > 0; } virtual void addChild(osg::Node& child) { // Add subface to parent. if (_parent.valid()) _parent->addChild(child); } virtual void addGeometry(osg::Geometry& geometry) { _geode->addDrawable(&geometry); } protected: virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); in.forward(4); int32 IRColor = in.readInt32(); /*int16 relativePriority =*/ in.readInt16(); _drawFlag = in.readUInt8(SOLID_NO_BACKFACE); uint8 texturedWhite = in.readUInt8(); int16 primaryNameIndex = in.readInt16(-1); /*int16 secondaryNameIndex =*/ in.readInt16(-1); in.forward(1); _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING); /*int detailTexture =*/ in.readInt16(-1); int textureIndex = in.readInt16(-1); int materialIndex = in.readInt16(-1); int16 surface = in.readInt16(); int16 feature = in.readInt16(); /*int32 IRMaterial =*/ in.readInt32(-1); _transparency = in.readUInt16(0); // version > 13 /*uint8 influenceLOD =*/ in.readUInt8(); /*uint8 linestyle =*/ in.readUInt8(); _flags = in.readUInt32(0); _lightMode = in.readUInt8(FACE_COLOR); in.forward(7); osg::Vec4 primaryPackedColor = in.readColor32(); /*osg::Vec4 secondaryPackedColor =*/ in.readColor32(); // version >= VERSION_15_1 /*int textureMappingIndex =*/ in.readInt16(-1); in.forward(2); int primaryColorIndex = in.readInt32(-1); /*int alternateColorIndex =*/ in.readInt32(-1); // version >= 16 in.forward(2); int shaderIndex = in.readInt16(-1); // Create Geode or Billboard. switch (_template) { case AXIAL_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::AXIAL_ROT); _geode = billboard; } break; case POINT_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::POINT_ROT_WORLD); _geode = billboard; } break; default: _geode = new osg::Geode; } _geode->setDataVariance(osg::Object::STATIC); _geode->setName(id); // StateSet osg::ref_ptr stateset = new osg::StateSet; // Hidden if (isHidden()) _geode->setNodeMask(0); // Face color if (texturedWhite!=0 && textureIndex>=0) { _primaryColor = osg::Vec4(1,1,1,1); } else { if (packedColorMode()) { _primaryColor = primaryPackedColor; } else { if (document.version() < VERSION_15_1) _primaryColor = document.getColorPool()->getColor(primaryNameIndex); else // >= VERSION_15_1 _primaryColor = document.getColorPool()->getColor(primaryColorIndex); } } // Lighting stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF); // Material if (isLit() || materialIndex>=0) { // MaterialPool will return a "default" material if no material is defined for materialIndex. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html osg::Vec4 col = _primaryColor; col.a() = 1.0f - getTransparency(); osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col); stateset->setAttribute(material); } // IRColor (IRC) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != IRColor) { _geode->setUserValue("", IRColor); } // surface (SMC) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != surface) { _geode->setUserValue("", surface); } // feature (FID) if (document.getPreserveNonOsgAttrsAsUserData() && 0 != feature) { _geode->setUserValue("", feature); } // Shaders if (shaderIndex >= 0) { ShaderPool* sp = document.getOrCreateShaderPool(); osg::Program* program = sp->get(shaderIndex); if (program) stateset->setAttributeAndModes(program, osg::StateAttribute::ON); } // Texture TexturePool* tp = document.getOrCreateTexturePool(); osg::StateSet* textureStateSet = tp->get(textureIndex); if (textureStateSet) { // Merge face stateset with texture stateset stateset->merge(*textureStateSet); } // Cull face switch(_drawFlag) { case SOLID_BACKFACED: // Enable backface culling { static osg::ref_ptr cullFace = new osg::CullFace(osg::CullFace::BACK); stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); break; } case SOLID_NO_BACKFACE: // Disable backface culling if( document.getReplaceDoubleSidedPolys( ) ) { static osg::ref_ptr cullFace = new osg::CullFace(osg::CullFace::BACK); stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); } else { stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); } break; } // Subface if (document.subfaceLevel() > 0) { stateset->setAttributeAndModes(document.getSubSurfacePolygonOffset(document.subfaceLevel()), osg::StateAttribute::ON); stateset->setAttribute(document.getSubSurfaceDepth()); stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin"); } _geode->setStateSet(stateset.get()); // Add to parent. if (_parent.valid()) _parent->addChild(*_geode); } virtual void dispose(Document& document) { if (_geode.valid()) { // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_geode,*_matrix,_numberOfReplications); } if( getDrawMode( ) == SOLID_NO_BACKFACE && document.getReplaceDoubleSidedPolys( ) ) { addDrawableAndReverseWindingOrder( _geode.get() ); } osg::StateSet* stateset = _geode->getOrCreateStateSet(); // Translucent image? bool isImageTranslucent = false; if (document.getUseTextureAlphaForTransparancyBinning()) { for (unsigned int i=0; igetTextureAttributeList().size(); ++i) { osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE); osg::Texture2D* texture = dynamic_cast(sa); if (texture) { osg::Image* image = texture->getImage(); if (image && image->isImageTranslucent()) isImageTranslucent = true; } } } // Transparent Material? bool isMaterialTransparent = false; osg::Material* material = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (material) { isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f; } // Enable alpha blend? if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent) { static osg::ref_ptr blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } if (document.getUseBillboardCenter()) { // Set billboard rotation point to center of face. osg::Billboard* billboard = dynamic_cast(_geode.get()); if (billboard) { for (unsigned int i=0; igetNumDrawables(); ++i) { const osg::BoundingBox& bb = billboard->getDrawable(i)->getBoundingBox(); billboard->setPosition(i,bb.center()); osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center())); billboard->getDrawable(i)->accept(tf); billboard->getDrawable(i)->dirtyBound(); } billboard->dirtyBound(); } } } } }; REGISTER_FLTRECORD(Mesh, MESH_OP) /** LocalVertexPool - */ class LocalVertexPool : public Record { // Attribute Mask static const unsigned int HAS_POSITION = 0x80000000u >> 0; static const unsigned int HAS_COLOR_INDEX = 0x80000000u >> 1; static const unsigned int HAS_RGBA_COLOR = 0x80000000u >> 2; static const unsigned int HAS_NORMAL = 0x80000000u >> 3; static const unsigned int HAS_BASE_UV = 0x80000000u >> 4; static const unsigned int HAS_UV_LAYER1 = 0x80000000u >> 5; static const unsigned int HAS_UV_LAYER2 = 0x80000000u >> 6; static const unsigned int HAS_UV_LAYER3 = 0x80000000u >> 7; static const unsigned int HAS_UV_LAYER4 = 0x80000000u >> 8; static const unsigned int HAS_UV_LAYER5 = 0x80000000u >> 9; static const unsigned int HAS_UV_LAYER6 = 0x80000000u >> 10; static const unsigned int HAS_UV_LAYER7 = 0x80000000u >> 11; public: LocalVertexPool() {} META_Record(LocalVertexPool) protected: virtual ~LocalVertexPool() {} virtual void readRecord(RecordInputStream& in, Document& document) { uint32 vertices = in.readUInt32(); uint32 mask = in.readUInt32(); osg::ref_ptr _vertexList = new VertexList(vertices); for (unsigned int n=0; n> 24; osg::Vec4 color = document.getColorPool()->getColor(index); color.a() = (float)alpha/255; vertex.setColor(color); if (!color.valid()) { OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord color="<> layer)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(layer,uv); if (!uv.valid()) { OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord uv="<setLocalVertexPool(_vertexList.get()); } }; REGISTER_FLTRECORD(LocalVertexPool, LOCAL_VERTEX_POOL_OP) /** MeshPrimitive - */ class MeshPrimitive : public PrimaryRecord { enum PrimitiveType { TRIANGLE_STRIP = 1, TRIANGLE_FAN = 2, QUADRILATERAL_STRIP = 3, INDEXED_POLYGON = 4 }; public: MeshPrimitive() {} META_Record(MeshPrimitive) protected: virtual ~MeshPrimitive() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { Mesh* mesh = dynamic_cast(_parent.get()); if (!mesh) return; VertexList* vertexList = mesh->getLocalVertexPool(); if (!vertexList) return; int16 type = in.readInt16(); uint16 indexSize = in.readUInt16(); uint32 vertexCount = in.readUInt32(); GLenum mode = 0; switch(type) { case TRIANGLE_STRIP: mode = osg::PrimitiveSet::TRIANGLE_STRIP; break; case TRIANGLE_FAN: mode = osg::PrimitiveSet::TRIANGLE_FAN; break; case QUADRILATERAL_STRIP: mode = osg::PrimitiveSet::QUAD_STRIP; break; case INDEXED_POLYGON: mode = osg::PrimitiveSet::POLYGON; break; } osg::ref_ptr geometry = new osg::Geometry; geometry->addPrimitiveSet(new osg::DrawArrays(mode,0,vertexCount)); for (unsigned int n=0; nsize()) { Vertex& vertex = (*vertexList)[index]; osg::Vec3Array* vertices = getOrCreateVertexArray(*geometry); vertices->push_back(vertex._coord); if (vertex.validColor()) { osg::Vec4Array* colors = getOrCreateColorArray(*geometry); colors->push_back(vertex._color); } if (vertex.validNormal()) { osg::Vec3Array* normals = getOrCreateNormalArray(*geometry); normals->push_back(vertex._normal); } for (int layer=0; layerpush_back(vertex._uv[layer]); } } } } // Color binding if (mesh->isGouraud()) { // Color per vertex if (geometry->getColorArray()) geometry->getColorArray()->setBinding(osg::Array::BIND_PER_VERTEX); } else { // Color per face osg::Vec4 col = mesh->getPrimaryColor(); col[3] = 1.0f - mesh->getTransparency(); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0] = col; geometry->setColorArray(colors, osg::Array::BIND_OVERALL); } // Normal binding if (mesh->isLit()) { if (geometry->getNormalArray()) geometry->getNormalArray()->setBinding(osg::Array::BIND_PER_VERTEX); } else { geometry->setNormalArray(0); } mesh->addGeometry(*geometry); } }; REGISTER_FLTRECORD(MeshPrimitive, MESH_PRIMITIVE_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Document.h0000644000175000017500000002736113151044751026002 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight� loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_FLIGHTDATA_H #define FLT_FLIGHTDATA_H 1 #include #include #include #include #include #include #include #include #include "Types.h" #include "Record.h" #include "Pools.h" namespace flt { class Header; class PushLevel; class PopLevel; enum Version { VERSION_11 = 11, VERSION_12 = 12, VERSION_13 = 13, VERSION_14 = 14, VERSION_14_1 = 14, VERSION_14_2 = 1420, VERSION_15_1 = 1510, VERSION_15_4 = 1540, VERSION_15_5 = 1550, VERSION_15_6 = 1560, VERSION_15_7 = 1570, VERSION_15_8 = 1580, VERSION_16_0 = 1600, VERSION_16_1 = 1610 }; enum CoordUnits { METERS = 0, KILOMETERS = 1, FEET = 4, INCHES = 5, NAUTICAL_MILES = 8 }; double unitsToMeters(CoordUnits unit); enum Projection { FLAT_EARTH = 0, TRAPEZOIDAL = 1, ROUND_EARTH = 2, LAMBERT = 3, UTM = 4, GEODETIC = 5, GEOCENTRIC = 6 }; enum Ellipsoid { WGS_1984 = 0, WGS_1972 = 1, BESSEL = 2, CLARKE_1866 = 3, NAD_1927 = 4 }; class Document { public: Document(); virtual ~Document(); void setOptions(const osgDB::ReaderWriter::Options* options) { _options = options; } const osgDB::ReaderWriter::Options* getOptions() const { return _options.get(); } // Current primary record void setCurrentPrimaryRecord(PrimaryRecord* record) { _currentPrimaryRecord=record; } PrimaryRecord* getCurrentPrimaryRecord() { return _currentPrimaryRecord.get(); } const PrimaryRecord* getCurrentPrimaryRecord() const { return _currentPrimaryRecord.get(); } // Level stack PrimaryRecord* getTopOfLevelStack(); void pushLevel(); void popLevel(); // Subface stack void pushSubface(); void popSubface(); // Extension stack void pushExtension(); void popExtension(); void setHeaderNode(osg::Node* node) { _osgHeader = node; } osg::Node* getHeaderNode() { return _osgHeader.get(); } // Instance definitions void setInstanceDefinition(int no, osg::Node* node) { _instanceDefinitionMap[no] = node; } osg::Node* getInstanceDefinition(int no); uint32 version() const { return _version; } bool done() const { return _done; } int level() const { return _level; } int subfaceLevel() const { return _subfaceLevel; } double unitScale() const { return _unitScale; } // Pools void setVertexPool(VertexPool* vp) { _vertexPool = vp; } VertexPool* getVertexPool() { return _vertexPool.get(); } const VertexPool* getVertexPool() const { return _vertexPool.get(); } void setColorPool(ColorPool* cp, bool parent=false) { _colorPool = cp; _colorPoolParent=parent; } ColorPool* getColorPool() { return _colorPool.get(); } const ColorPool* getColorPool() const { return _colorPool.get(); } bool getColorPoolParent() const { return _colorPoolParent; } void setTexturePool(TexturePool* tp, bool parent=false) { _texturePool = tp; _texturePoolParent=parent; } TexturePool* getTexturePool() { return _texturePool.get(); } TexturePool* getOrCreateTexturePool(); bool getTexturePoolParent() const { return _texturePoolParent; } void setMaterialPool(MaterialPool* mp, bool parent=false) { _materialPool = mp; _materialPoolParent=parent; } MaterialPool* getMaterialPool() { return _materialPool.get(); } MaterialPool* getOrCreateMaterialPool(); bool getMaterialPoolParent() const { return _materialPoolParent; } void setLightSourcePool(LightSourcePool* lsp, bool parent=false) { _lightSourcePool = lsp; _lightSourcePoolParent=parent; } LightSourcePool* getLightSourcePool() { return _lightSourcePool.get(); } LightSourcePool* getOrCreateLightSourcePool(); bool getLightSourcePoolParent() const { return _lightSourcePoolParent; } void setLightPointAppearancePool(LightPointAppearancePool* lpap, bool parent=false) { _lightPointAppearancePool = lpap; _lightPointAppearancePoolParent=parent; } LightPointAppearancePool* getLightPointAppearancePool() { return _lightPointAppearancePool.get(); } LightPointAppearancePool* getOrCreateLightPointAppearancePool(); bool getLightPointAppearancePoolParent() const { return _lightPointAppearancePoolParent; } void setLightPointAnimationPool(LightPointAnimationPool* lpap, bool parent=false) { _lightPointAnimationPool = lpap; _lightPointAnimationPoolParent=parent; } LightPointAnimationPool* getLightPointAnimationPool() { return _lightPointAnimationPool.get(); } LightPointAnimationPool* getOrCreateLightPointAnimationPool(); bool getLightPointAnimationPoolParent() const { return _lightPointAnimationPoolParent; } void setShaderPool(ShaderPool* cp, bool parent=false) { _shaderPool = cp; _shaderPoolParent=parent; } ShaderPool* getShaderPool() { return _shaderPool.get(); } ShaderPool* getOrCreateShaderPool(); bool getShaderPoolParent() const { return _shaderPoolParent; } void setSubSurfacePolygonOffset(int level, osg::PolygonOffset* po); osg::PolygonOffset* getSubSurfacePolygonOffset(int level); void setSubSurfaceDepth(osg::Depth* depth) { _subsurfaceDepth = depth; } osg::Depth* getSubSurfaceDepth() { return _subsurfaceDepth.get(); } // Options void setReplaceClampWithClampToEdge(bool flag) { _replaceClampWithClampToEdge = flag; } bool getReplaceClampWithClampToEdge() const { return _replaceClampWithClampToEdge; } void setPreserveFace(bool flag) { _preserveFace = flag; } bool getPreserveFace() const { return _preserveFace; } void setPreserveObject(bool flag) { _preserveObject = flag; } bool getPreserveObject() const { return _preserveObject; } void setReplaceDoubleSidedPolys(bool flag) { _replaceDoubleSidedPolys = flag; } bool getReplaceDoubleSidedPolys() const { return _replaceDoubleSidedPolys; } void setDefaultDOFAnimationState(bool state) { _defaultDOFAnimationState = state; } bool getDefaultDOFAnimationState() const { return _defaultDOFAnimationState; } void setUseTextureAlphaForTransparancyBinning(bool flag) { _useTextureAlphaForTransparancyBinning=flag; } bool getUseTextureAlphaForTransparancyBinning() const { return _useTextureAlphaForTransparancyBinning; } void setUseBillboardCenter(bool flag) { _useBillboardCenter=flag; } bool getUseBillboardCenter() const { return _useBillboardCenter; } void setDoUnitsConversion(bool flag) { _doUnitsConversion=flag; } bool getDoUnitsConversion() const { return _doUnitsConversion; } void setDesiredUnits(CoordUnits units ) { _desiredUnits=units; } CoordUnits getDesiredUnits() const { return _desiredUnits; } void setKeepExternalReferences( bool flag) { _keepExternalReferences=flag; } bool getKeepExternalReferences() const { return _keepExternalReferences; } void setReadObjectRecordData(bool flag) { _readObjectRecordData = flag; } bool getReadObjectRecordData() const { return _readObjectRecordData; } void setPreserveNonOsgAttrsAsUserData(bool flag) { _preserveNonOsgAttrsAsUserData = flag; } bool getPreserveNonOsgAttrsAsUserData() const { return _preserveNonOsgAttrsAsUserData; } protected: // Options osg::ref_ptr _options; bool _replaceClampWithClampToEdge; bool _preserveFace; bool _preserveObject; bool _replaceDoubleSidedPolys; bool _defaultDOFAnimationState; bool _useTextureAlphaForTransparancyBinning; bool _useBillboardCenter; bool _doUnitsConversion; bool _readObjectRecordData; bool _preserveNonOsgAttrsAsUserData; CoordUnits _desiredUnits; bool _keepExternalReferences; friend class Header; bool _done; int _level; int _subfaceLevel; double _unitScale; uint32 _version; // Header data osg::ref_ptr _osgHeader; osg::ref_ptr _vertexPool; osg::ref_ptr _colorPool; osg::ref_ptr _texturePool; osg::ref_ptr _materialPool; osg::ref_ptr _lightSourcePool; osg::ref_ptr _lightPointAppearancePool; osg::ref_ptr _lightPointAnimationPool; osg::ref_ptr _shaderPool; typedef std::map > SubSurfacePolygonOffsets; SubSurfacePolygonOffsets _subsurfacePolygonOffsets; osg::ref_ptr _subsurfaceDepth; bool _colorPoolParent; bool _texturePoolParent; bool _materialPoolParent; bool _lightSourcePoolParent; bool _lightPointAppearancePoolParent; bool _lightPointAnimationPoolParent; bool _shaderPoolParent; osg::ref_ptr _currentPrimaryRecord; typedef std::vector > LevelStack; LevelStack _levelStack; LevelStack _extensionStack; typedef std::map > InstanceDefinitionMap; InstanceDefinitionMap _instanceDefinitionMap; }; inline TexturePool* Document::getOrCreateTexturePool() { if (!_texturePool.valid()) _texturePool = new TexturePool; return _texturePool.get(); } inline MaterialPool* Document::getOrCreateMaterialPool() { if (!_materialPool.valid()) _materialPool = new MaterialPool; return _materialPool.get(); } inline LightSourcePool* Document::getOrCreateLightSourcePool() { if (!_lightSourcePool.valid()) _lightSourcePool = new LightSourcePool; return _lightSourcePool.get(); } inline LightPointAppearancePool* Document::getOrCreateLightPointAppearancePool() { if (!_lightPointAppearancePool.valid()) _lightPointAppearancePool = new LightPointAppearancePool; return _lightPointAppearancePool.get(); } inline LightPointAnimationPool* Document::getOrCreateLightPointAnimationPool() { if (!_lightPointAnimationPool.valid()) _lightPointAnimationPool = new LightPointAnimationPool; return _lightPointAnimationPool.get(); } inline ShaderPool* Document::getOrCreateShaderPool() { if (!_shaderPool.valid()) _shaderPool = new ShaderPool; return _shaderPool.get(); } inline PrimaryRecord* Document::getTopOfLevelStack() { // Anything on the level stack? if (_levelStack.empty()) return NULL; return _levelStack.back().get(); } } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Pools.cpp0000644000175000017500000001051613151044751025645 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include "Pools.h" #include "Document.h" using namespace flt; osg::Vec4 ColorPool::getColor(int indexIntensity) const { if (_old) // version <= 13 { // bit 0-6: intensity // bit 7-11 color index // bit 12 fixed intensity bit bool fixedIntensity = (indexIntensity & 0x1000) ? true : false; unsigned int index = (fixedIntensity) ? (indexIntensity & 0x0fff)+(4096>>7) : indexIntensity >> 7; if (index>=size()) { // color index not available. return osg::Vec4(1,1,1,1); } osg::Vec4 col = operator[](index); if (!fixedIntensity) { float intensity = (float)(indexIntensity & 0x7f)/127.f; col[0] *= intensity; col[1] *= intensity; col[2] *= intensity; } return col; } else // version > 13 { // bit 0-6: intensity // bit 7-15 color index unsigned int index = indexIntensity >> 7; if (index>=size()) { // color index not available. return osg::Vec4(1,1,1,1); } osg::Vec4 col = operator[](index); float intensity = (float)(indexIntensity & 0x7f)/127.f; col[0] *= intensity; col[1] *= intensity; col[2] *= intensity; return col; } } MaterialPool::MaterialPool() { // Default material. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html _defaultMaterial = new osg::Material; _defaultMaterial->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1,1,1,1)); _defaultMaterial->setDiffuse (osg::Material::FRONT_AND_BACK,osg::Vec4(1,1,1,1)); _defaultMaterial->setSpecular(osg::Material::FRONT_AND_BACK,osg::Vec4(0,0,0,1)); _defaultMaterial->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0,0,0,1)); _defaultMaterial->setShininess(osg::Material::FRONT_AND_BACK,0); } osg::Material* MaterialPool::get(int index) { iterator itr = find(index); if (itr != end()) return (*itr).second.get(); // Use default material if not found in material palette. return _defaultMaterial.get(); } namespace { osg::Vec4 finalColor(const osg::Vec4& materialColor, const osg::Vec4& faceColor) { return osg::Vec4( materialColor.r() * faceColor.r(), materialColor.g() * faceColor.g(), materialColor.b() * faceColor.b(), materialColor.a() * faceColor.a()); } } // end namespace osg::Material* MaterialPool::getOrCreateMaterial(int index, const osg::Vec4& faceColor) { MaterialParameters materialParam(index,faceColor); // Look for final material. FinalMaterialMap::iterator itr = _finalMaterialMap.find(materialParam); if (itr != _finalMaterialMap.end()) { // Final material found. return (*itr).second.get(); } osg::Material* poolMaterial = get(index); // Create final material. osg::Material* material = dynamic_cast(poolMaterial->clone(osg::CopyOp::SHALLOW_COPY)); osg::Vec4 materialPaletteAmbient = poolMaterial->getAmbient(osg::Material::FRONT); osg::Vec4 materialPaletteDiffuse = poolMaterial->getDiffuse(osg::Material::FRONT); material->setAmbient(osg::Material::FRONT_AND_BACK, finalColor(materialPaletteAmbient, faceColor)); material->setDiffuse(osg::Material::FRONT_AND_BACK, finalColor(materialPaletteDiffuse, faceColor)); material->setAlpha(osg::Material::FRONT_AND_BACK, materialPaletteAmbient.a()*faceColor.a()); // Set final material so it can be reused. _finalMaterialMap[materialParam] = material; return material; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/FltWriteResult.h0000644000175000017500000000357713151044751027166 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLT_WRITE_RESULT_H__ #define __FLT_WRITE_RESULT_H__ 1 #include #include #include #include #include #include #include namespace flt { /*! Custom WriteResult to support proxy/validation ("validate" Option). If the application is able to #include this header and obtain the Writeresult from osgDB, then the app can query this class for warning or error conditions due to scene graph incompatibility with FLT. */ class FltWriteResult : public osgDB::ReaderWriter::WriteResult { public: FltWriteResult( WriteResult::WriteStatus status=WriteResult::FILE_SAVED ) : WriteResult( status ) {} void setNumErrors( int n ); int getNumErrors() const; void setNumWarnings( int n ); int getNumWarnings() const; typedef std::pair< osg::NotifySeverity, std::string > MessagePair; typedef std::vector< MessagePair > MessageVector; void warn( const std::string &ss ) { messages_.push_back( std::make_pair( osg::WARN, ss ) ); } void error( const std::string &ss ) { messages_.push_back( std::make_pair( osg::FATAL, ss ) ); } protected: MessageVector messages_; }; } #endif /* __OPEN_FLIGHT_WRITER_H__ */ OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/expControlRecords.cpp0000644000175000017500000000230713151044751030227 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "FltExportVisitor.h" #include "DataOutputStream.h" #include "Opcodes.h" namespace flt { void FltExportVisitor::writePush() { _records->writeInt16( (int16) PUSH_LEVEL_OP ); _records->writeInt16( 4 ); } void FltExportVisitor::writePop() { _records->writeInt16( (int16) POP_LEVEL_OP ); _records->writeInt16( 4 ); } void FltExportVisitor::writePushSubface() { _records->writeInt16( (int16) PUSH_SUBFACE_OP ); _records->writeInt16( 4 ); } void FltExportVisitor::writePopSubface() { _records->writeInt16( (int16) POP_SUBFACE_OP ); _records->writeInt16( 4 ); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Document.cpp0000644000175000017500000000673013151044751026332 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight� loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include "Document.h" using namespace flt; Document::Document() : _replaceClampWithClampToEdge(false), _preserveFace(false), _preserveObject(false), _replaceDoubleSidedPolys(false), _defaultDOFAnimationState(false), _useTextureAlphaForTransparancyBinning(true), _useBillboardCenter(false), _doUnitsConversion(true), _readObjectRecordData(false), _preserveNonOsgAttrsAsUserData(false), _desiredUnits(METERS), _done(false), _level(0), _subfaceLevel(0), _unitScale(1.0), _version(0), _colorPoolParent(false), _texturePoolParent(false), _materialPoolParent(false), _lightSourcePoolParent(false), _lightPointAppearancePoolParent(false), _lightPointAnimationPoolParent(false), _shaderPoolParent(false) { _subsurfaceDepth = new osg::Depth(osg::Depth::LESS, 0.0, 1.0,false); } Document::~Document() { } void Document::pushLevel() { _levelStack.push_back(_currentPrimaryRecord.get()); _level++; } void Document::popLevel() { _levelStack.pop_back(); if (!_levelStack.empty()) _currentPrimaryRecord = _levelStack.back(); if (--_level<=0) _done = true; } void Document::pushSubface() { _subfaceLevel++; } void Document::popSubface() { _subfaceLevel--; } void Document::pushExtension() { if (!_currentPrimaryRecord.valid()) { OSG_WARN << "No current primary in Document::pushExtension()." << std::endl; return; } _extensionStack.push_back(_currentPrimaryRecord.get()); } void Document::popExtension() { _currentPrimaryRecord=_extensionStack.back().get(); if (!_currentPrimaryRecord.valid()) { OSG_WARN << "Can't decide primary in Document::popExtension()." << std::endl; return; } _extensionStack.pop_back(); } osg::Node* Document::getInstanceDefinition(int no) { InstanceDefinitionMap::iterator itr = _instanceDefinitionMap.find(no); if (itr != _instanceDefinitionMap.end()) return (*itr).second.get(); return NULL; } void Document::setSubSurfacePolygonOffset(int level, osg::PolygonOffset* po) { _subsurfacePolygonOffsets[level] = po; } osg::PolygonOffset* Document::getSubSurfacePolygonOffset(int level) { OSG_DEBUG<<"Document::getSubSurfacePolygonOffset("<& po = _subsurfacePolygonOffsets[level]; if (!po) { po = new osg::PolygonOffset(-1.0f*float(level), -1.0f); } return po.get(); } double flt::unitsToMeters(CoordUnits unit) { switch (unit) { case METERS: return 1.0; case KILOMETERS: return 1000.0; case FEET: return 0.3048; case INCHES: return 0.02540; case NAUTICAL_MILES: return 1852.0; } return 1.0; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/AttrData.cpp0000644000175000017500000000472113151044751026256 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include "AttrData.h" using namespace flt; AttrData::AttrData() : texels_u(0), texels_v(0), direction_u(0), direction_v(0), x_up(0), y_up(0), fileFormat(-1), // -1 Not used minFilterMode(MIN_FILTER_NONE), magFilterMode(MAG_FILTER_POINT), wrapMode(WRAP_REPEAT), wrapMode_u(WRAP_REPEAT), wrapMode_v(WRAP_REPEAT), modifyFlag(0), pivot_x(0), pivot_y(0), texEnvMode(TEXENV_MODULATE), intensityAsAlpha(0), size_u(0), size_v(0), originCode(0), kernelVersion(0), intFormat(0), // 0 - Default extFormat(0), // 0 - Default useMips(0), useLodScale(0), lod0(0.0f), scale0(1.0f), lod1(0.0f), scale1(1.0f), lod2(0.0f), scale2(1.0f), lod3(0.0f), scale3(1.0f), lod4(0.0f), scale4(1.0f), lod5(0.0f), scale5(1.0f), lod6(0.0f), scale6(1.0f), lod7(0.0f), scale7(1.0f), clamp(0), magFilterAlpha(2), // 2 = None magFilterColor(2), // 2 = None lambertMeridian(0), lambertUpperLat(0), lambertlowerLat(0), useDetail(0), txDetail_j(0), txDetail_k(0), txDetail_m(0), txDetail_n(0), txDetail_s(0), useTile(0), txTile_ll_u(0), txTile_ll_v(0), txTile_ur_u(0), txTile_ur_v(0), projection(PROJECTION_UNDEFINED), earthModel(DATUM_WGS84), utmZone(0), imageOrigin(0), geoUnits(0), hemisphere(1), comments(""), attrVersion(0), controlPoints(0) // TODO: { of_mips[0]=of_mips[1]=of_mips[2]=of_mips[3]=of_mips[4]=of_mips[5]=of_mips[6]=of_mips[7]=0.0f; } AttrData::AttrData(const AttrData& attr, const osg::CopyOp& copyop) : osg::Object(attr,copyop) {} OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/MaterialPaletteManager.h0000644000175000017500000000352113151044751030564 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_MATERIAL_PALETTE_MANAGER_H__ #define __FLTEXP_MATERIAL_PALETTE_MANAGER_H__ 1 #include "ExportOptions.h" #include namespace osg { class Material; } namespace flt { class DataOutputStream; class MaterialPaletteManager { public: MaterialPaletteManager( ExportOptions& fltOpt ); // Add a material to the palette and auto-assign it the next available index int add(osg::Material const* material); // Write the material palette records out to a DataOutputStream void write( DataOutputStream& dos ) const; private: int _currIndex; // Helper struct to hold material palette records struct MaterialRecord { MaterialRecord(osg::Material const* m, int i) : Material(m) , Index(i) { } osg::Material const* Material; int Index; }; // Map to allow lookups by Material pointer, and permit sorting by index typedef std::map MaterialPalette; MaterialPalette _materialPalette; ExportOptions& _fltOpt; protected: MaterialPaletteManager& operator = (const MaterialPaletteManager&) { return *this; } }; } // End namespace fltexp #endif // !FLTEXP_MATERIAL_PALETTE_MANAGER_H OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/RecordInputStream.h0000644000175000017500000000261513151044751027631 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_RECORDINPUTSTREAM_H #define FLT_RECORDINPUTSTREAM_H 1 #include "Record.h" #include "DataInputStream.h" namespace flt { class Document; typedef int opcode_type; typedef std::streamsize size_type; class RecordInputStream : public DataInputStream { public: explicit RecordInputStream(std::streambuf* sb); bool readRecord(Document&); bool readRecordBody(opcode_type, size_type, Document&); inline std::streamsize getRecordSize() const { return _recordSize; } inline std::streamsize getRecordBodySize() const { return _recordSize-(std::streamsize)4; } protected: std::streamsize _recordSize; }; } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/RecordInputStream.cpp0000644000175000017500000000475613151044751030174 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include "Opcodes.h" #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" using namespace flt; using namespace std; RecordInputStream::RecordInputStream(std::streambuf* sb): DataInputStream(sb), _recordSize(0) {} bool RecordInputStream::readRecord(Document& document) { opcode_type opcode = (opcode_type)readUInt16(); size_type size = (size_type)readUInt16(); return readRecordBody(opcode, size, document); } bool RecordInputStream::readRecordBody(opcode_type opcode, size_type size, Document& document) { // Correct endian error in Creator v2.5 gallery models. // Last pop level record in little-endian. const uint16 LITTLE_ENDIAN_POP_LEVEL_OP = 0x0B00; if (opcode==LITTLE_ENDIAN_POP_LEVEL_OP) { OSG_INFO << "Little endian pop-level record" << std::endl; opcode=POP_LEVEL_OP; size=4; } _recordSize = size; // Get prototype record Record* prototype = Registry::instance()->getPrototype((int)opcode); if (prototype) { #if 0 // for debugging { for (int i=0; i record = prototype->cloneType(); // Read record record->read(*this,document); } else // prototype not found { OSG_WARN << "Unknown record, opcode=" << opcode << " size=" << size << std::endl; // Add to registry so we only have to see this error message once. Registry::instance()->addPrototype(opcode,new DummyRecord); } return good(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Record.cpp0000644000175000017500000001045213151044751025766 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include "Record.h" #include "Document.h" using namespace flt; Record::Record() { } Record::~Record() { } void Record::read(RecordInputStream& in, Document& document) { _parent = document.getCurrentPrimaryRecord(); // Read record body. readRecord(in,document); } void Record::readRecord(RecordInputStream& /*in*/, Document& /*document*/) { } PrimaryRecord::PrimaryRecord() : _numberOfReplications(0) { } void PrimaryRecord::read(RecordInputStream& in, Document& document) { PrimaryRecord* parentPrimary = document.getTopOfLevelStack(); PrimaryRecord* currentPrimary = document.getCurrentPrimaryRecord(); // Finally call dispose() for primary without push, pop level pair. if (currentPrimary && currentPrimary!=parentPrimary) { currentPrimary->dispose(document); } // Update current primary record. document.setCurrentPrimaryRecord(this); _parent = parentPrimary; // Read record body. readRecord(in,document); } /////////////////////////////////////////////////////////////////////////////////// // Helper methods // Insert matrix-tranform(s) // // node: node to apply transform // matrix: transformation matrix // numberOfReplications: zero for regular transform, number of copies if replication is used. void flt::insertMatrixTransform(osg::Node& node, const osg::Matrix& matrix, int numberOfReplications) { osg::ref_ptr ref = &node; osg::Node::ParentList parents = node.getParents(); // Start without transformation if replication. osg::Matrix accumulatedMatrix = (numberOfReplications > 0)? osg::Matrix::identity() : matrix; for (int n=0; n<=numberOfReplications; n++) { // Accumulate transformation for each replication. osg::ref_ptr transform = new osg::MatrixTransform(accumulatedMatrix); transform->setDataVariance(osg::Object::STATIC); // Add transform to parents for (osg::Node::ParentList::iterator itr=parents.begin(); itr!=parents.end(); ++itr) { (*itr)->replaceChild(&node, transform.get()); } // Make primary a child of matrix transform. transform->addChild(&node); // Accumulate transform if multiple replications. accumulatedMatrix *= matrix; } } /////////////////////////////////////////////////////////////////////////////////// osg::Vec3Array* flt::getOrCreateVertexArray(osg::Geometry& geometry) { osg::Vec3Array* vertices = dynamic_cast(geometry.getVertexArray()); if (!vertices) { vertices = new osg::Vec3Array; geometry.setVertexArray(vertices); } return vertices; } osg::Vec3Array* flt::getOrCreateNormalArray(osg::Geometry& geometry) { osg::Vec3Array* normals = dynamic_cast(geometry.getNormalArray()); if (!normals) { normals = new osg::Vec3Array; geometry.setNormalArray(normals); } return normals; } osg::Vec4Array* flt::getOrCreateColorArray(osg::Geometry& geometry) { osg::Vec4Array* colors = dynamic_cast(geometry.getColorArray()); if (!colors) { colors = new osg::Vec4Array; geometry.setColorArray(colors); } return colors; } osg::Vec2Array* flt::getOrCreateTextureArray(osg::Geometry& geometry, int unit) { osg::Vec2Array* UVs = dynamic_cast(geometry.getTexCoordArray(unit)); if (!UVs) { UVs = new osg::Vec2Array; geometry.setTexCoordArray(unit,UVs); } return UVs; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/DataOutputStream.cpp0000644000175000017500000000765513151044751030031 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "DataOutputStream.h" #include #include using namespace flt; char DataOutputStream::_null( 0 ); DataOutputStream::DataOutputStream( std::streambuf* sb, bool validate ) : std::ostream( sb ), _validate( validate ) { _byteswap = osg::getCpuByteOrder() == osg::LittleEndian; } void DataOutputStream::writeInt8( const int8 val ) { vwrite( (char*)&val, sizeof( int8 ) ); } void DataOutputStream::writeUInt8( const uint8 val ) { vwrite( (char*)&val, sizeof( uint8 ) ); } void DataOutputStream::writeInt16( const int16 val ) { int16 data=val; if (_byteswap && good()) osg::swapBytes2( (char*)&data ); vwrite( (char*)&data, sizeof( int16 ) ); } void DataOutputStream::writeUInt16( const uint16 val ) { uint16 data=val; if (_byteswap && good()) osg::swapBytes2( (char*)&data ); vwrite( (char*)&data, sizeof( uint16 ) ); } void DataOutputStream::writeInt32( const int32 val ) { int32 data=val; if (_byteswap && good()) osg::swapBytes4( (char*)&data ); vwrite( (char*)&data, sizeof( int32 ) ); } void DataOutputStream::writeUInt32( const uint32 val ) { uint32 data=val; if (_byteswap && good()) osg::swapBytes4( (char*)&data ); vwrite( (char*)&data, sizeof( uint32 ) ); } void DataOutputStream::writeFloat32( const float32 val ) { float32 data=val; if (_byteswap && good()) osg::swapBytes4( (char*)&data ); vwrite( (char*)&data, sizeof( float32 ) ); } void DataOutputStream::writeFloat64( const float64 val ) { float64 data=val; if (_byteswap && good()) osg::swapBytes8( (char*)&data ); vwrite( (char*)&data, sizeof( float64 ) ); } void DataOutputStream::writeString( const std::string& val, bool nullTerminate ) { vwrite( const_cast( val.c_str() ), val.size() ); if (nullTerminate) vwrite( &_null, 1 ); } void DataOutputStream::writeString( const std::string& val, int size, char fill ) { if (val.size() > ((unsigned int)size)-1) { vwrite( const_cast( val.c_str() ), size-1 ); vwrite( &fill, 1 ); } else { vwrite( const_cast( val.c_str() ), val.size() ); writeFill( size - val.size(), fill ); } } void DataOutputStream::writeID( const std::string& val ) { unsigned int len = val.size(); vwrite( const_cast( val.c_str() ), len ); while (len++ < 8) vwrite( &_null, 1 ); } void DataOutputStream::writeVec2f( const osg::Vec2f& val ) { writeFloat32( val.x() ); writeFloat32( val.y() ); } void DataOutputStream::writeVec3f( const osg::Vec3f& val ) { writeFloat32( val.x() ); writeFloat32( val.y() ); writeFloat32( val.z() ); } void DataOutputStream::writeVec4f( const osg::Vec4f& val ) { writeFloat32( val.x() ); writeFloat32( val.y() ); writeFloat32( val.z() ); writeFloat32( val.w() ); } void DataOutputStream::writeVec3d( const osg::Vec3d& val ) { writeFloat64( val.x() ); writeFloat64( val.y() ); writeFloat64( val.z() ); } void DataOutputStream::writeFill( int sizeBytes, const char val ) { for (int i = 0; i < sizeBytes; ++i) { put(val); } } std::ostream& DataOutputStream::vwrite( char_type* str, std::streamsize count ) { if (_validate) return *this; else return write( str, count ); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/ExportOptions.cpp0000644000175000017500000001753313151044751027414 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include #include #include #include #include #include #include "ExportOptions.h" #include #include namespace flt { /** @name Valid Option Strings * This plugin supports the following \c Option string values. */ //@{ /** Value: "version". * Specifies the version of the output OpenFlight file. Supported values * include 15.7, 15.8, and 16.1. Default is 16.1. Example: * "version=15.8". */ std::string ExportOptions::_versionOption( "version" ); /** Value: "units". * Specifies the contents of the \c Units field of the OpenFliht header record. * Valid values include INCHES, FEET, METERS, KILOMETERS, and NATICAL_MILES. * Default is METERS. Example: "units=METERS". */ std::string ExportOptions::_unitsOption( "units" ); /** Value: "validate". * If present in the Options string, the plugin does not write an OpenFlight file. * Instead, it returns an indication of the scene graph's suitability for * OpenFlight export. */ std::string ExportOptions::_validateOption( "validate" ); /** Value: "tempDir". * Specifies the directory to use for creation of temporary files. If not * specified, the directory is taken from the file name. If the file doesn't * contain a path, the current working directory is used. Applications should * set this to the name of their app-specific temp directory. If the path * contains spaces, use double quotes to ensure correct parsing. Examples: * "tempDir=/tmp". * "tempDir=\"C:\\My Temp Dir\"". */ std::string ExportOptions::_tempDirOption( "tempDir" ); /** Value: "lighting". * Specifies a default enable/disable state for lighting, for Nodes in the * exported scene graph that don't set it explicitly. By default, the * exporter assumes lighting is enabled (GL_LIGHTING ON). Set this to * either ON or OFF. Example: * "lighting=OFF". */ std::string ExportOptions::_lightingOption( "lighting" ); /** Value: "stripTextureFilePath". * If present in the Options string, the exporter strips the path from * texture file names, and writes only the texture file name to the FLT * Texture Palette. By default, the exporter doesn't strip the path, * and the name written to the Texture Palette is taken directly from * the osg::Image object referenced by the osg::Texture2D StateAttribute. */ std::string ExportOptions::_stripTextureFilePathOption( "stripTextureFilePath" ); //@} using namespace osgDB; const int ExportOptions::VERSION_15_7( 1570 ); const int ExportOptions::VERSION_15_8( 1580 ); const int ExportOptions::VERSION_16_1( 1610 ); ExportOptions::ExportOptions() : _version( VERSION_16_1 ), _units( METERS ), _validate( false ), _lightingDefault( true ), _stripTextureFilePath( false ) { } ExportOptions::ExportOptions( const osgDB::ReaderWriter::Options* opt ) : _version( VERSION_16_1 ), _units( METERS ), _validate( false ), _lightingDefault( true ), _stripTextureFilePath( false ) { if (opt) { const ExportOptions* fltOpt = dynamic_cast( opt ); if (fltOpt) { _version = fltOpt->_version; _units = fltOpt->_units; _validate = fltOpt->_validate; _tempDir = fltOpt->_tempDir; _lightingDefault = fltOpt->_lightingDefault; } setOptionString( opt->getOptionString() ); } } void ExportOptions::parseOptionsString() { // Parse out the option string and store values directly in // ExportOptions member variables. const std::string& str = getOptionString(); if (str.empty()) return; std::string::size_type pos( 0 ); while (pos != str.npos) { // Skip leading spaces. while ( (pos < str.length()) && (str[pos] == ' ') ) pos++; // Get the next token std::string::size_type count = str.substr( pos ).find_first_of( " =" ); std::string token = str.substr( pos, count ); if (count == str.npos) pos = str.npos; else pos += (count+1); // See if it's a Boolen/toggle if ( token == _validateOption ) { OSG_INFO << "fltexp: Found: " << token << std::endl; setValidateOnly( true ); continue; } if ( token == _stripTextureFilePathOption ) { OSG_INFO << "fltexp: Found: " << token << std::endl; setStripTextureFilePath( true ); continue; } // Protect against unrecognized options without values if ( pos == str.npos ) { OSG_WARN << "fltexp: Bogus OptionString: " << token << std::endl; continue; } // Not a Boolean/toggle. Must have a value. // Get the value of the token, which could be double-quoted. if( str[pos] == '"' ) { ++pos; count = str.substr( pos ).find_first_of( '"' ); } else count = str.substr( pos ).find_first_of( ' ' ); std::string value = str.substr( pos, count ); if (count == str.npos) pos = str.npos; else pos += (count+1); if (token == _versionOption) { OSG_INFO << "fltexp: Token: " << token << ", Value: " << value << std::endl; int version( VERSION_16_1 ); if( value == std::string( "15.7" ) ) version = VERSION_15_7; else if( value == std::string( "15.8" ) ) version = VERSION_15_8; else if( value != std::string( "16.1" ) ) OSG_WARN << "fltexp: Unsupported version: " << value << ". Defaulting to 16.1." << std::endl; setFlightFileVersionNumber( version ); } else if (token == _unitsOption) { OSG_INFO << "fltexp: Token: " << token << ", Value: " << value << std::endl; FlightUnits units( METERS ); if( value == std::string( "KILOMETERS" ) ) units = KILOMETERS; else if( value == std::string( "FEET" ) ) units = FEET; else if( value == std::string( "INCHES" ) ) units = INCHES; else if( value == std::string( "NAUTICAL_MILES" ) ) units = NAUTICAL_MILES; else if( value != std::string( "METERS" ) ) OSG_WARN << "fltexp: Unsupported units: " << value << ". Defaulting to METERS." << std::endl; setFlightUnits( units ); } else if (token == _tempDirOption) { OSG_INFO << "fltexp: Token: " << token << ", Value: " << value << std::endl; setTempDir( value ); } else if (token == _lightingOption) { OSG_INFO << "fltexp: Token: " << token << ", Value: " << value << std::endl; bool lighting( true ); if (value == std::string( "OFF" ) ) lighting = false; else if (value != std::string( "ON" ) ) OSG_WARN << "fltexp: Unsupported lighting value: " << value << ". Defaulting to ON." << std::endl; setLightingDefault( lighting ); } else OSG_WARN << "fltexp: Bogus OptionString: " << token << std::endl; } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/LightSourcePaletteManager.cpp0000644000175000017500000000664413151044751031622 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "LightSourcePaletteManager.h" #include "DataOutputStream.h" #include "Opcodes.h" #include #include #include #include #include #include namespace flt { LightSourcePaletteManager::LightSourcePaletteManager() : _currIndex( -1 ) { // TODO: Pay attention to the version here(?) } int LightSourcePaletteManager::add(osg::Light const* light) { int index = -1; if (light == NULL) return -1; // If this light has already been cached, set 'index' to the cached value LightPalette::const_iterator it = _lightPalette.find(light); if ( it != _lightPalette.end() ) { index = it->second.Index; } // New light? Add it to the cache... else { index = ++_currIndex; _lightPalette.insert(std::make_pair(light, LightRecord(light, index) ) ); } return index; } void LightSourcePaletteManager::write( DataOutputStream& dos ) const { using osg::Vec4f; static int const INFINITE_LIGHT = 0; static int const LOCAL_LIGHT = 1; static int const SPOT_LIGHT = 2; LightPalette::const_iterator it = _lightPalette.begin(); for ( ; it != _lightPalette.end(); ++it) { LightRecord m = it->second; static char lightName[64]; sprintf(lightName, "Light%02d", m.Light->getLightNum() ); int lightType = INFINITE_LIGHT; Vec4f const& lightPos = m.Light->getPosition(); if (lightPos.w() != 0) { if (m.Light->getSpotCutoff() < 180) lightType = SPOT_LIGHT; else lightType = LOCAL_LIGHT; } dos.writeInt16( (int16) LIGHT_SOURCE_PALETTE_OP ); dos.writeInt16( 240 ); dos.writeInt32( m.Index ); dos.writeFill(2*4, '\0'); // Reserved dos.writeString( lightName, 20 ); dos.writeFill(4, '\0'); // Reserved dos.writeVec4f(m.Light->getAmbient() ); dos.writeVec4f(m.Light->getDiffuse() ); dos.writeVec4f(m.Light->getSpecular() ); dos.writeInt32(lightType); dos.writeFill(4*10, '\0'); // Reserved dos.writeFloat32(m.Light->getSpotExponent() ); dos.writeFloat32(m.Light->getSpotCutoff() ); dos.writeFloat32(0); // Yaw (N/A) dos.writeFloat32(0); // Pitch (N/A) dos.writeFloat32(m.Light->getConstantAttenuation() ); dos.writeFloat32(m.Light->getLinearAttenuation() ); dos.writeFloat32(m.Light->getQuadraticAttenuation() ); dos.writeInt32(0); // Modeling flag (N/A) dos.writeFill(4*19, '\0'); // Reserved } } } // End namespace fltexp OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/MaterialPaletteManager.cpp0000644000175000017500000000726213151044751031125 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "MaterialPaletteManager.h" #include "DataOutputStream.h" #include "Opcodes.h" #include #include #include #include #include namespace flt { MaterialPaletteManager::MaterialPaletteManager( ExportOptions& fltOpt ) : _currIndex( -1 ), _fltOpt( fltOpt ) { // TODO: Pay attention to the version here(?) } int MaterialPaletteManager::add(osg::Material const* material) { int index = -1; if (material == NULL) return -1; // If this material has already been cached, set 'index' to the cached value MaterialPalette::const_iterator it = _materialPalette.find(material); if ( it != _materialPalette.end() ) { index = it->second.Index; } // New material? Add it to the cache... else { index = ++_currIndex; _materialPalette.insert(std::make_pair(material, MaterialRecord(material, index) ) ); } return index; } void MaterialPaletteManager::write( DataOutputStream& dos ) const { using osg::Vec4f; MaterialPalette::const_iterator it = _materialPalette.begin(); for ( ; it != _materialPalette.end(); ++it) { MaterialRecord m = it->second; Vec4f const& ambient = m.Material->getAmbient(osg::Material::FRONT); Vec4f const& diffuse = m.Material->getDiffuse(osg::Material::FRONT); Vec4f const& specular = m.Material->getSpecular(osg::Material::FRONT); Vec4f const& emissive = m.Material->getEmission(osg::Material::FRONT); float shininess = m.Material->getShininess(osg::Material::FRONT); dos.writeInt16( (int16) MATERIAL_PALETTE_OP ); dos.writeInt16( 84 ); // Length - FIXME: hard-code/FLT version? dos.writeInt32( m.Index ); dos.writeString( m.Material->getName(), 12 ); dos.writeInt32( 0 ); // Flags dos.writeFloat32(ambient.r() ); dos.writeFloat32(ambient.g() ); dos.writeFloat32(ambient.b() ); dos.writeFloat32(diffuse.r() ); dos.writeFloat32(diffuse.g() ); dos.writeFloat32(diffuse.b() ); dos.writeFloat32(specular.r() ); dos.writeFloat32(specular.g() ); dos.writeFloat32(specular.b() ); dos.writeFloat32(emissive.r() ); dos.writeFloat32(emissive.g() ); dos.writeFloat32(emissive.b() ); dos.writeFloat32(shininess); dos.writeFloat32( diffuse.a() ); // alpha dos.writeFloat32(1.0f); // 'Reserved' - unused if (m.Material->getAmbientFrontAndBack() == false || m.Material->getDiffuseFrontAndBack() == false || m.Material->getSpecularFrontAndBack() == false || m.Material->getEmissionFrontAndBack() == false || m.Material->getShininessFrontAndBack() == false ) { std::string warning( "fltexp: No support for different front and back material properties." ); OSG_WARN << warning << std::endl; _fltOpt.getWriteResult().warn( warning ); } } } } // End namespace fltexp OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/CMakeLists.txt0000644000175000017500000000225513151044751026606 0ustar albertoalbertoSET(TARGET_SRC AncillaryRecords.cpp AttrData.cpp ControlRecords.cpp DataInputStream.cpp DataOutputStream.cpp Document.cpp expAncillaryRecords.cpp expControlRecords.cpp expGeometryRecords.cpp expPrimaryRecords.cpp ExportOptions.cpp FltExportVisitor.cpp GeometryRecords.cpp LightPointRecords.cpp LightSourcePaletteManager.cpp MaterialPaletteManager.cpp PaletteRecords.cpp Pools.cpp PrimaryRecords.cpp ReaderWriterATTR.cpp ReaderWriterFLT.cpp Record.cpp RecordInputStream.cpp Registry.cpp ReservedRecords.cpp RoadRecords.cpp TexturePaletteManager.cpp Vertex.cpp VertexPaletteManager.cpp VertexRecords.cpp ) SET(TARGET_H AttrData.h DataInputStream.h DataOutputStream.h ExportOptions.h FltExportVisitor.h FltWriteResult.h Document.h LightSourcePaletteManager.h MaterialPaletteManager.h Pools.h Record.h RecordInputStream.h Registry.h TexturePaletteManager.h Vertex.h VertexPaletteManager.h Opcodes.h Types.h Utils.h ) SET(TARGET_ADDED_LIBRARIES osgSim ) #### end var setup ### SETUP_PLUGIN(openflight) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Opcodes.h0000644000175000017500000001305513151044751025613 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_OPCODES_H #define FLT_OPCODES_H namespace flt { // Note that INVALID_OP = -1 is not an actual opcode defined in the OpenFlight format. // The purpose of INVALID_OP is to mark an opcode variable as invalid or uninitialized. enum Opcodes { INVALID_OP = -1, UNKNOWN_OP = 0, HEADER_OP = 1, GROUP_OP = 2, OLD_LOD_OP = 3, OBJECT_OP = 4, FACE_OP = 5, OLD_ABSOLUTE_VERTEX_OP = 7, OLD_SHADED_VERTEX_OP = 8, OLD_NORMAL_VERTEX_OP = 9, PUSH_LEVEL_OP = 10, POP_LEVEL_OP = 11, DOF_OP = 14, PUSH_SUBFACE_OP = 19, POP_SUBFACE_OP = 20, PUSH_EXTENSION_OP = 21, POP_EXTENSION_OP = 22, CONTINUATION_OP = 23, COMMENT_OP = 31, COLOR_PALETTE_OP = 32, LONG_ID_OP = 33, OLD_TRANSLATE_OP = 40, OLD_ROTATE_ABOUT_POINT_OP = 41, OLD_ROTATE_ABOUT_EDGE_OP = 42, OLD_SCALE_OP = 43, OLD_TRANSLATE2_OP = 44, OLD_NONUNIFORM_SCALE_OP = 45, OLD_ROTATE_ABOUT_POINT2_OP = 46, OLD_ROTATE_SCALE_TO_POINT_OP = 47, OLD_PUT_TRANSFORM_OP = 48, MATRIX_OP = 49, VECTOR_OP = 50, OLD_BOUNDING_BOX_OP = 51, MULTITEXTURE_OP = 52, UV_LIST_OP = 53, BINARY_SEPARATING_PLANE_OP = 55, REPLICATE_OP = 60, INSTANCE_REFERENCE_OP = 61, INSTANCE_DEFINITION_OP = 62, EXTERNAL_REFERENCE_OP = 63, TEXTURE_PALETTE_OP = 64, OLD_EYEPOINT_PALETTE_OP = 65, OLD_MATERIAL_PALETTE_OP = 66, VERTEX_PALETTE_OP = 67, VERTEX_C_OP = 68, VERTEX_CN_OP = 69, VERTEX_CNT_OP = 70, VERTEX_CT_OP = 71, VERTEX_LIST_OP = 72, LOD_OP = 73, BOUNDING_BOX_OP = 74, ROTATE_ABOUT_EDGE_OP = 76, SCALE_OP = 77, TRANSLATE_OP = 78, NONUNIFORM_SCALE_OP = 79, ROTATE_ABOUT_POINT_OP = 80, ROTATE_SCALE_TO_POINT_OP = 81, PUT_TRANSFORM_OP = 82, EYEPOINT_AND_TRACKPLANE_PALETTE_OP = 83, MESH_OP = 84, LOCAL_VERTEX_POOL_OP = 85, MESH_PRIMITIVE_OP = 86, ROAD_SEGMENT_OP = 87, ROAD_ZONE_OP = 88, MORPH_VERTEX_LIST_OP = 89, LINKAGE_PALETTE_OP = 90, SOUND_OP = 91, ROAD_PATH_OP = 92, SOUND_PALETTE_OP = 93, GENERAL_MATRIX_OP = 94, TEXT_OP = 95, SWITCH_OP = 96, LINE_STYLE_PALETTE_OP = 97, CLIP_REGION_OP = 98, EXTENSION_OP = 100, LIGHT_SOURCE_OP = 101, LIGHT_SOURCE_PALETTE_OP = 102, BOUNDING_SPHERE_OP = 105, BOUNDING_CYLINDER_OP = 106, BOUNDING_CONVEX_HULL_OP = 107, BOUNDING_VOLUME_CENTER_OP = 108, BOUNDING_VOLUME_ORIENTATION_OP = 109, HISTOGRAM_BOUNDING_VOLUME_OP = 110, LIGHT_POINT_OP = 111, TEXTURE_MAPPING_PALETTE_OP = 112, MATERIAL_PALETTE_OP = 113, NAME_TABLE_OP = 114, CAT_OP = 115, CAT_DATA_OP = 116, BOUNDING_HISTOGRAM = 119, PUSH_ATTRIBUTE_OP = 122, POP_ATTRIBUTE_OP = 123, ADAPTIVE_ATTRIBUTE_OP = 125, CURVE_NODE_OP = 126, ROAD_CONSTRUCTION_OP = 127, LIGHT_POINT_APPEARANCE_PALETTE_OP = 128, LIGHT_POINT_ANIMATION_PALETTE_OP = 129, INDEXED_LIGHT_POINT_OP = 130, LIGHT_POINT_SYSTEM_OP = 131, INDEXED_STRING_OP = 132, SHADER_PALETTE_OP = 133 }; } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/ExportOptions.h0000644000175000017500000000547413151044751027062 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLT_EXPORT_OPTIONS_H__ #define __FLT_EXPORT_OPTIONS_H__ 1 #include "FltWriteResult.h" #include #include #include #include #include #include #include namespace flt { /*! Options class for controlling export behavior. Features a parser for the Option string as well as getter methods for supported options. */ class ExportOptions : public osgDB::Options { public: ExportOptions( const Options* opt ); ExportOptions(); static const int VERSION_15_7; static const int VERSION_15_8; static const int VERSION_16_1; enum FlightUnits { METERS, KILOMETERS, FEET, INCHES, NAUTICAL_MILES }; void setFlightFileVersionNumber( int num ) { _version = num; } int getFlightFileVersionNumber() const { return _version; } void setFlightUnits( FlightUnits units ) { _units = units; } FlightUnits getFlightUnits() const { return _units; } void setValidateOnly( bool validate ) { _validate = validate; } bool getValidateOnly() const { return _validate; } void setTempDir( const std::string& dir ) { _tempDir = dir; } std::string getTempDir() const { return _tempDir; } void setLightingDefault( bool lighting ) { _lightingDefault = lighting; } bool getLightingDefault() const { return _lightingDefault; } void setStripTextureFilePath( bool strip ) { _stripTextureFilePath = strip; } bool getStripTextureFilePath() const { return _stripTextureFilePath; } FltWriteResult & getWriteResult() const { return( wr_ ); } // Parse the OptionString and override values based on // what was set in the OptionString. void parseOptionsString(); protected: int _version; FlightUnits _units; bool _validate; std::string _tempDir; bool _lightingDefault; bool _stripTextureFilePath; mutable FltWriteResult wr_; static std::string _versionOption; static std::string _unitsOption; static std::string _validateOption; static std::string _tempDirOption; static std::string _lightingOption; static std::string _stripTextureFilePathOption; }; } #endif /* __OPEN_FLIGHT_WRITER_H__ */ OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/DataOutputStream.h0000644000175000017500000000430613151044751027464 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_DATA_OUTPUT_STREAM_H__ #define __FLTEXP_DATA_OUTPUT_STREAM_H__ 1 #include #include #include #include #include #include "Types.h" //#include "Export.h" namespace flt { class Record; class DataOutputStream : public std::ostream { public: explicit DataOutputStream( std::streambuf* sb, bool validate=false ); void writeInt8( const int8 val ); void writeUInt8( const uint8 val ); void writeInt16( const int16 val ); void writeUInt16( const uint16 val ); void writeInt32( const int32 val ); void writeUInt32( const uint32 val ); void writeFloat32( const float32 val ); void writeFloat64( const float64 val ); // Write the entire string. If nullTerminate is true, write an additional NULL. // Always writes either 'val.size()' bytes or 'val.size()+1' bytes. void writeString( const std::string& val, bool nullTerminate=true ); // Never write more than 'size-1' bytes from 'val', and write 'fill' so that 'size' bytes total are written. // Always writes 'size' bytes.. void writeString( const std::string& val, int size, char fill='\0' ); void writeID( const std::string& val ); void writeVec2f( const osg::Vec2f& val ); void writeVec3f( const osg::Vec3f& val ); void writeVec4f( const osg::Vec4f& val ); void writeVec3d( const osg::Vec3d& val ); void writeFill( int sizeBytes, const char val='\0' ); protected: virtual std::ostream& vwrite( char_type* str, std::streamsize count ); bool _byteswap; bool _validate; static char _null; }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Vertex.h0000644000175000017500000000342513151044751025474 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_VERTEX_H #define FLT_VERTEX_H 1 #include #include #include #include #include namespace flt { class Vertex { public: Vertex(); Vertex(const Vertex& vertex); void setCoord(const osg::Vec3& coord); void setColor(const osg::Vec4& color); void setNormal(const osg::Vec3& normal); void setUV(int layer, const osg::Vec2& uv); bool validColor() const { return _validColor; } bool validNormal() const { return _validNormal; } bool validUV(int layer) const { return layer>=0 && layer { public: VertexList() {} explicit VertexList(int size) : std::vector(size) {} protected: virtual ~VertexList() {} }; } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Pools.h0000644000175000017500000002325613151044751025317 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_POOLS_H #define FLT_POOLS_H 1 #include #include #include #include #include #include #include #include #include "Types.h" namespace flt { class VertexPool : public osg::Referenced, public std::istringstream { public: explicit VertexPool( const std::string& str) : std::istringstream(str,std::istringstream::in|std::istringstream::binary) {} protected: virtual ~VertexPool() {} }; class ColorPool : public osg::Referenced , public std::vector { public: explicit ColorPool(bool old,int size) : std::vector(size), _old(old) {} osg::Vec4 getColor(int indexIntensity) const; protected: virtual ~ColorPool() {} bool _old; // true if version <= 13 }; class TexturePool : public osg::Referenced , public std::map > { public: TexturePool() {} osg::StateSet* get(int index) { iterator itr = find(index); if (itr != end()) return (*itr).second.get(); return NULL; } protected: virtual ~TexturePool() {} }; class MaterialPool : public osg::Referenced , public std::map > { public: MaterialPool(); // Get material, return default material if not found in palette. osg::Material* get(int index); // Get or create material based on // index: face material index // color: face color with alpha set to 1-face transparency. osg::Material* getOrCreateMaterial(int index, const osg::Vec4& faceColor); protected: virtual ~MaterialPool() {} osg::ref_ptr _defaultMaterial; struct MaterialParameters { int index; // face index to material pool osg::Vec4 color; // face color with alpha set to 1-face transparency. MaterialParameters(): index(-1) {} MaterialParameters(int i, const osg::Vec4& c): index(i), color(c) {} bool operator < (const MaterialParameters& rhs) const { if (index < rhs.index) return true; else if (index > rhs.index) return false; else return (color < rhs.color); } }; // Material from palette combined with face color stored here for reuse. typedef std::map > FinalMaterialMap; FinalMaterialMap _finalMaterialMap; }; class LightSourcePool : public osg::Referenced , public std::map > { public: LightSourcePool() {} osg::Light* get(int index) { iterator itr = find(index); if (itr != end()) return (*itr).second.get(); return NULL; } protected: virtual ~LightSourcePool() {} }; struct LPAppearance : public osg::Referenced { std::string name; int32 index; int16 materialCode; int16 featureID; osg::Vec4f backColor; int32 displayMode; float32 intensityFront; float32 intensityBack; float32 minDefocus; float32 maxDefocus; int32 fadingMode; int32 fogPunchMode; int32 directionalMode; int32 rangeMode; float32 minPixelSize; float32 maxPixelSize; float32 actualPixelSize; float32 transparentFalloffPixelSize; float32 transparentFalloffExponent; float32 transparentFalloffScalar; float32 transparentFalloffClamp; float32 fogScalar; float32 fogIntensity; float32 sizeDifferenceThreshold; int32 directionality; float32 horizontalLobeAngle; float32 verticalLobeAngle; float32 lobeRollAngle; float32 directionalFalloffExponent; float32 directionalAmbientIntensity; float32 significance; uint32 flags; float32 visibilityRange; float32 fadeRangeRatio; float32 fadeInDuration; float32 fadeOutDuration; float32 LODRangeRatio; float32 LODScale; int16 texturePatternIndex; }; class LightPointAppearancePool : public osg::Referenced , public std::map > { public: LightPointAppearancePool() {} LPAppearance* get(int index) { iterator itr = find(index); if (itr != end()) return (*itr).second.get(); return NULL; } protected: virtual ~LightPointAppearancePool() {} }; struct LPAnimation : public osg::Referenced { enum AnimationType { FLASHING_SEQUENCE = 0, ROTATING = 1, STROBE = 2, MORSE_CODE = 3 }; enum State { ON = 0, OFF = 1, COLOR_CHANGE = 2 }; struct Pulse { uint32 state; float32 duration; osg::Vec4 color; }; typedef std::vector PulseArray; std::string name; // animation name int32 index; // animation index float32 animationPeriod; // animation period, in seconds float32 animationPhaseDelay; // animation phase delay, in seconds from start of period float32 animationEnabledPeriod; // animation enabled period (time on), in seconds osg::Vec3f axisOfRotation; // axis of rotation for rotating animation (i, j, k) uint32 flags; // flags (bits, from left to right) // 0 = flashing // 1 = rotating // 2 = rotate counter clockwise // 3-31 = spare int32 animationType; // animation type // 0 = flashing sequence // 1 = rotating // 2 = strobe // 3 = morse code int32 morseCodeTiming; // morse code timing // 0 = standard timing // 1 = Farnsworth timing int32 wordRate; // word rate (for Farnsworth timing) int32 characterRate; // character rate (for Farnsworth timing) std::string morseCodeString; // morse code string PulseArray sequence; }; class LightPointAnimationPool : public osg::Referenced , public std::map > { public: LightPointAnimationPool() {} LPAnimation* get(int index) { iterator itr = find(index); if (itr != end()) return (*itr).second.get(); return NULL; } protected: virtual ~LightPointAnimationPool() {} }; class ShaderPool : public osg::Referenced , public std::map > { public: ShaderPool() {} osg::Program* get(int index) { iterator itr = find(index); if (itr != end()) return (*itr).second.get(); return NULL; } protected: virtual ~ShaderPool() {} }; // This object records parent palettes for external record support. // When an external record is parsed, this object is instantiated and populated with // the parent model's palettes, then stored as UserData on the ProxyNode. // When the ReadExternalsVisitor hits the ProxyNode, it moves this object // into the ReaderWriter Options' UserData before calling osgDB::ReadNode, // enabling access to the parent palettes during load of the ext ref model. class ParentPools : public osg::Referenced { public: ParentPools() {} void setColorPool(ColorPool* pool) { _colorPool=pool; } ColorPool* getColorPool() const { return _colorPool.get(); } void setTexturePool(TexturePool* pool) { _texturePool=pool; } TexturePool* getTexturePool() const { return _texturePool.get(); } void setMaterialPool(MaterialPool* pool) { _materialPool=pool; } MaterialPool* getMaterialPool() const { return _materialPool.get(); } void setLightSourcePool(LightSourcePool* pool) { _lightSourcePool=pool; } LightSourcePool* getLightSourcePool() const { return _lightSourcePool.get(); } void setLPAppearancePool(LightPointAppearancePool* pool) { _lpAppearancePool=pool; } LightPointAppearancePool* getLPAppearancePool() const { return _lpAppearancePool.get(); } void setLPAnimationPool(LightPointAnimationPool* pool) { _lpAnimationPool=pool; } LightPointAnimationPool* getLPAnimationPool() const { return _lpAnimationPool.get(); } void setShaderPool(ShaderPool* pool) { _shaderPool=pool; } ShaderPool* getShaderPool() const { return _shaderPool.get(); } protected: virtual ~ParentPools() {} osg::ref_ptr _colorPool; osg::ref_ptr _materialPool; osg::ref_ptr _texturePool; osg::ref_ptr _lightSourcePool; osg::ref_ptr _lpAppearancePool; osg::ref_ptr _lpAnimationPool; osg::ref_ptr _shaderPool; }; } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/AncillaryRecords.cpp0000644000175000017500000002544013151044751030013 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" namespace flt { /** Comment - */ class Comment : public Record { public: Comment() {} META_Record(Comment) protected: virtual ~Comment() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { std::streamsize size = in.getRecordSize(); std::string commentfield = in.readString(size-4); if (_parent.valid()) { #if 0 _parent->setComment(commentfield); #else unsigned int front_of_line = 0; unsigned int end_of_line = 0; while (end_of_linesetComment( std::string( commentfield, front_of_line, end_of_line-front_of_line) ); if (end_of_line+1setComment( std::string( commentfield, front_of_line, end_of_line-front_of_line) ); ++end_of_line; front_of_line = end_of_line; } else ++end_of_line; } if (front_of_linesetComment( std::string( commentfield, front_of_line, end_of_line-front_of_line) ); } } #endif } }; REGISTER_FLTRECORD(Comment, COMMENT_OP) /** LongID - */ class LongID : public Record { public: LongID() {} META_Record(LongID) protected: virtual ~LongID() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { std::streamsize size = in.getRecordSize(); std::string id = in.readString(size-4); if (_parent.valid()) _parent->setID(id); } }; REGISTER_FLTRECORD(LongID, LONG_ID_OP) /** Matrix - */ class Matrix : public Record { public: Matrix() {} META_Record(Matrix) protected: virtual ~Matrix() {} virtual void readRecord(RecordInputStream& in, Document& document) { osg::Matrix matrix; for (int i=0; i<4; ++i) { for (int j=0; j<4; ++j) { matrix(i,j) = in.readFloat32(); } } // scale position. osg::Vec3 pos = matrix.getTrans(); matrix *= osg::Matrix::translate(-pos); pos *= (float)document.unitScale(); matrix *= osg::Matrix::translate(pos); if (_parent.valid()) _parent->setMatrix(matrix); } }; REGISTER_FLTRECORD(Matrix, MATRIX_OP) /** Multitexture - */ class Multitexture : public Record { public: Multitexture() {} META_Record(Multitexture) // Effect enum EffectMode { TEXTURE_ENVIRONMENT = 0, BUMP_MAP = 1 }; protected: virtual ~Multitexture() {} virtual void readRecord(RecordInputStream& in, Document& document) { osg::ref_ptr stateset = new osg::StateSet; uint32 mask = in.readUInt32(); for (int layer=1; layer<8; layer++) { uint32 layerBit = 0x80000000u >> (layer-1); if (mask & layerBit) { int16 textureIndex = in.readInt16(); int16 effect = in.readInt16(); /*int16 mappingIndex =*/ in.readInt16(); /*uint16 data =*/ in.readUInt16(); osg::ref_ptr texturePoolStateset = document.getOrCreateTexturePool()->get(textureIndex); if (stateset.valid() && texturePoolStateset.valid()) { // Apply texture from texture pool. osg::Texture* texture = dynamic_cast(texturePoolStateset->getTextureAttribute(0,osg::StateAttribute::TEXTURE)); if (texture) stateset->setTextureAttributeAndModes(layer,texture,osg::StateAttribute::ON); // Apply texture environment switch (effect) { case TEXTURE_ENVIRONMENT: { // Use texture environment setting from .attr file. osg::TexEnv* texenv = dynamic_cast(texturePoolStateset->getTextureAttribute(0,osg::StateAttribute::TEXENV)); if (texenv) stateset->setTextureAttribute(layer,texenv); } break; case BUMP_MAP: { // Dot3 bumpmap //osg::TexEnvCombine* texEnvCombine = new osg::TexEnvCombine; //texEnvCombine->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB); //texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PRIMARY_COLOR); //texEnvCombine->setSource1_RGB(osg::TexEnvCombine::TEXTURE); //stateset->setTextureAttribute(layer,texEnvCombine); } break; } } } } if (_parent.valid()) _parent->setMultitexture(*stateset); } }; REGISTER_FLTRECORD(Multitexture, MULTITEXTURE_OP) /** UVList - Texture coordinates used with multitexture. UVList is an ancillary to VertexList. */ class UVList : public Record { public: UVList() {} META_Record(UVList) protected: virtual ~UVList() {} // count number of 1's in mask. int bitCount(uint32 mask) { int count = 0; while (mask) { if (mask & 0x0001) ++count; mask >>= 1; } return count; } virtual void readRecord(RecordInputStream& in, Document& /*document*/) { uint32 mask = in.readUInt32(0); int numLayers = bitCount(mask); int numVertices = (in.getRecordSize()-8) / (8 * numLayers); for (int n=0; n < numVertices; ++n) { for (unsigned int layer=1; layer<8; layer++) { uint32 layerBit = 0x80000000u >> (layer-1); if (mask & layerBit) { float32 u = in.readFloat32(); float32 v = in.readFloat32(); // Add texture coordinates to geometry. if (_parent.valid()) _parent->addVertexUV(layer,osg::Vec2(u,v)); } } } } }; REGISTER_FLTRECORD(UVList, UV_LIST_OP) /** Replicate - */ class Replicate : public Record { public: Replicate() {} META_Record(Replicate) protected: virtual ~Replicate() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { int16 replicate = in.readInt16(); if (_parent.valid()) _parent->setNumberOfReplications((int)replicate); } }; REGISTER_FLTRECORD(Replicate, REPLICATE_OP) /** IndexedString - */ class IndexedString : public Record { public: IndexedString() {} META_Record(IndexedString) protected: virtual ~IndexedString() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { std::streamsize size = in.getRecordSize(); uint32 index = in.readUInt32(); std::string name = in.readString(size-8); if (_parent.valid()) _parent->setMultiSwitchValueName(index, name); } }; REGISTER_FLTRECORD(IndexedString, INDEXED_STRING_OP) // Prevent "unknown record" message for the following ancillary records: REGISTER_FLTRECORD(DummyRecord, OLD_TRANSLATE2_OP) REGISTER_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_POINT_OP) REGISTER_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_EDGE_OP) REGISTER_FLTRECORD(DummyRecord, OLD_SCALE_OP) REGISTER_FLTRECORD(DummyRecord, OLD_TRANSLATE_OP) REGISTER_FLTRECORD(DummyRecord, OLD_NONUNIFORM_SCALE_OP) REGISTER_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_POINT2_OP) REGISTER_FLTRECORD(DummyRecord, OLD_ROTATE_SCALE_TO_POINT_OP) REGISTER_FLTRECORD(DummyRecord, OLD_PUT_TRANSFORM_OP) REGISTER_FLTRECORD(DummyRecord, OLD_BOUNDING_BOX_OP) REGISTER_FLTRECORD(DummyRecord, ROAD_ZONE_OP) REGISTER_FLTRECORD(DummyRecord, ROTATE_ABOUT_EDGE_OP) REGISTER_FLTRECORD(DummyRecord, TRANSLATE_OP) REGISTER_FLTRECORD(DummyRecord, NONUNIFORM_SCALE_OP) REGISTER_FLTRECORD(DummyRecord, ROTATE_ABOUT_POINT_OP) REGISTER_FLTRECORD(DummyRecord, ROTATE_SCALE_TO_POINT_OP) REGISTER_FLTRECORD(DummyRecord, PUT_TRANSFORM_OP) REGISTER_FLTRECORD(DummyRecord, GENERAL_MATRIX_OP) REGISTER_FLTRECORD(DummyRecord, VECTOR_OP) REGISTER_FLTRECORD(DummyRecord, BOUNDING_BOX_OP) REGISTER_FLTRECORD(DummyRecord, BOUNDING_SPHERE_OP) REGISTER_FLTRECORD(DummyRecord, BOUNDING_CYLINDER_OP) REGISTER_FLTRECORD(DummyRecord, BOUNDING_CONVEX_HULL_OP) REGISTER_FLTRECORD(DummyRecord, BOUNDING_HISTOGRAM) REGISTER_FLTRECORD(DummyRecord, BOUNDING_VOLUME_CENTER_OP) REGISTER_FLTRECORD(DummyRecord, BOUNDING_VOLUME_ORIENTATION_OP) REGISTER_FLTRECORD(DummyRecord, HISTOGRAM_BOUNDING_VOLUME_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp0000644000175000017500000006663113151044751027527 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include #include #include #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" #include "DataOutputStream.h" #include "FltExportVisitor.h" #include "ExportOptions.h" #define SERIALIZER() OpenThreads::ScopedLock lock(_serializerMutex) using namespace flt; using namespace osg; using namespace osgDB; // pull in symbols from attr plugin USE_OSGPLUGIN(attr) // pull in symbols from individual .o's to enable the static build to work // note, following USE_FLTRECORD list was generated by running: // grep REGISTER_FLTRECORD * -h | grep -v "#define" | sed 's/REGISTER_FLTRECORD/USE_FLTRECORD/g' USE_FLTRECORD(Comment, COMMENT_OP) USE_FLTRECORD(LongID, LONG_ID_OP) USE_FLTRECORD(Matrix, MATRIX_OP) USE_FLTRECORD(Multitexture, MULTITEXTURE_OP) USE_FLTRECORD(UVList, UV_LIST_OP) USE_FLTRECORD(Replicate, REPLICATE_OP) USE_FLTRECORD(DummyRecord, OLD_TRANSLATE2_OP) USE_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_POINT_OP) USE_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_EDGE_OP) USE_FLTRECORD(DummyRecord, OLD_SCALE_OP) USE_FLTRECORD(DummyRecord, OLD_TRANSLATE_OP) USE_FLTRECORD(DummyRecord, OLD_NONUNIFORM_SCALE_OP) USE_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_POINT2_OP) USE_FLTRECORD(DummyRecord, OLD_ROTATE_SCALE_TO_POINT_OP) USE_FLTRECORD(DummyRecord, OLD_PUT_TRANSFORM_OP) USE_FLTRECORD(DummyRecord, OLD_BOUNDING_BOX_OP) USE_FLTRECORD(DummyRecord, INDEXED_STRING_OP) USE_FLTRECORD(DummyRecord, ROAD_ZONE_OP) USE_FLTRECORD(DummyRecord, ROTATE_ABOUT_EDGE_OP) USE_FLTRECORD(DummyRecord, TRANSLATE_OP) USE_FLTRECORD(DummyRecord, NONUNIFORM_SCALE_OP) USE_FLTRECORD(DummyRecord, ROTATE_ABOUT_POINT_OP) USE_FLTRECORD(DummyRecord, ROTATE_SCALE_TO_POINT_OP) USE_FLTRECORD(DummyRecord, PUT_TRANSFORM_OP) USE_FLTRECORD(DummyRecord, GENERAL_MATRIX_OP) USE_FLTRECORD(DummyRecord, VECTOR_OP) USE_FLTRECORD(DummyRecord, BOUNDING_BOX_OP) USE_FLTRECORD(DummyRecord, BOUNDING_SPHERE_OP) USE_FLTRECORD(DummyRecord, BOUNDING_CYLINDER_OP) USE_FLTRECORD(DummyRecord, BOUNDING_CONVEX_HULL_OP) USE_FLTRECORD(DummyRecord, BOUNDING_HISTOGRAM) USE_FLTRECORD(DummyRecord, BOUNDING_VOLUME_CENTER_OP) USE_FLTRECORD(DummyRecord, BOUNDING_VOLUME_ORIENTATION_OP) USE_FLTRECORD(DummyRecord, HISTOGRAM_BOUNDING_VOLUME_OP) USE_FLTRECORD(PushLevel, PUSH_LEVEL_OP) USE_FLTRECORD(PopLevel, POP_LEVEL_OP) USE_FLTRECORD(PushSubface, PUSH_SUBFACE_OP) USE_FLTRECORD(PopSubface, POP_SUBFACE_OP) USE_FLTRECORD(PushExtension, PUSH_EXTENSION_OP) USE_FLTRECORD(PopExtension, POP_EXTENSION_OP) USE_FLTRECORD(PushAttribute, PUSH_ATTRIBUTE_OP) USE_FLTRECORD(PopAttribute, POP_ATTRIBUTE_OP) USE_FLTRECORD(Face, FACE_OP) USE_FLTRECORD(VertexListRecord, VERTEX_LIST_OP) USE_FLTRECORD(MorphVertexList, MORPH_VERTEX_LIST_OP) USE_FLTRECORD(Mesh, MESH_OP) USE_FLTRECORD(LocalVertexPool, LOCAL_VERTEX_POOL_OP) USE_FLTRECORD(MeshPrimitive, MESH_PRIMITIVE_OP) USE_FLTRECORD(LightPoint, LIGHT_POINT_OP) USE_FLTRECORD(IndexedLightPoint, INDEXED_LIGHT_POINT_OP) USE_FLTRECORD(LightPointSystem, LIGHT_POINT_SYSTEM_OP) USE_FLTRECORD(VertexPalette, VERTEX_PALETTE_OP) USE_FLTRECORD(ColorPalette, COLOR_PALETTE_OP) USE_FLTRECORD(NameTable, NAME_TABLE_OP) USE_FLTRECORD(MaterialPalette, MATERIAL_PALETTE_OP) USE_FLTRECORD(OldMaterialPalette, OLD_MATERIAL_PALETTE_OP) USE_FLTRECORD(TexturePalette, TEXTURE_PALETTE_OP) USE_FLTRECORD(EyepointAndTrackplanePalette, EYEPOINT_AND_TRACKPLANE_PALETTE_OP) USE_FLTRECORD(LinkagePalette, LINKAGE_PALETTE_OP) USE_FLTRECORD(SoundPalette, SOUND_PALETTE_OP) USE_FLTRECORD(LightSourcePalette, LIGHT_SOURCE_PALETTE_OP) USE_FLTRECORD(LightPointAppearancePalette, LIGHT_POINT_APPEARANCE_PALETTE_OP) USE_FLTRECORD(LightPointAnimationPalette, LIGHT_POINT_ANIMATION_PALETTE_OP) USE_FLTRECORD(LineStylePalette, LINE_STYLE_PALETTE_OP) USE_FLTRECORD(TextureMappingPalette, TEXTURE_MAPPING_PALETTE_OP) USE_FLTRECORD(ShaderPalette, SHADER_PALETTE_OP) USE_FLTRECORD(Header, HEADER_OP) USE_FLTRECORD(Group, GROUP_OP) USE_FLTRECORD(DegreeOfFreedom, DOF_OP) USE_FLTRECORD(LevelOfDetail, LOD_OP) USE_FLTRECORD(OldLevelOfDetail, OLD_LOD_OP) USE_FLTRECORD(Switch, SWITCH_OP) USE_FLTRECORD(ExternalReference, EXTERNAL_REFERENCE_OP) USE_FLTRECORD(InstanceDefinition, INSTANCE_DEFINITION_OP) USE_FLTRECORD(InstanceReference, INSTANCE_REFERENCE_OP) USE_FLTRECORD(Extension, EXTENSION_OP) USE_FLTRECORD(Object, OBJECT_OP) USE_FLTRECORD(LightSource, LIGHT_SOURCE_OP) USE_FLTRECORD(DummyRecord, 103) USE_FLTRECORD(DummyRecord, 104) USE_FLTRECORD(DummyRecord, 117) USE_FLTRECORD(DummyRecord, 118) USE_FLTRECORD(DummyRecord, 120) USE_FLTRECORD(DummyRecord, 121) USE_FLTRECORD(DummyRecord, 124) USE_FLTRECORD(DummyRecord, 125) USE_FLTRECORD(RoadSegment, ROAD_SEGMENT_OP) USE_FLTRECORD(RoadConstruction, ROAD_CONSTRUCTION_OP) USE_FLTRECORD(RoadPath, ROAD_PATH_OP) USE_FLTRECORD(VertexC, VERTEX_C_OP) USE_FLTRECORD(VertexCN, VERTEX_CN_OP) USE_FLTRECORD(VertexCT, VERTEX_CT_OP) USE_FLTRECORD(VertexCNT, VERTEX_CNT_OP) USE_FLTRECORD(AbsoluteVertex, OLD_ABSOLUTE_VERTEX_OP) USE_FLTRECORD(ShadedVertex, OLD_SHADED_VERTEX_OP) USE_FLTRECORD(NormalVertex, OLD_NORMAL_VERTEX_OP) class ReadExternalsVisitor : public osg::NodeVisitor { osg::ref_ptr _options; bool _cloneExternalReferences; public: ReadExternalsVisitor(ReaderWriter::Options* options) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _options(options), _cloneExternalReferences(false) { if (options) _cloneExternalReferences = (options->getOptionString().find("cloneExternalReferences")!=std::string::npos); } virtual ~ReadExternalsVisitor() {} virtual void apply(ProxyNode& node) { // Transfer ownership of pools. _options->setUserData( node.getUserData() ); node.setUserData(NULL); for (unsigned int pos=0; pos external = osgDB::readRefNodeFile(filename,_options.get()); if (external.valid()) { if (_cloneExternalReferences) external = dynamic_cast(external->clone(osg::CopyOp(osg::CopyOp::DEEP_COPY_NODES))); node.addChild(external.get()); } } } }; /*! FLTReaderWriter supports importing and exporting OSG scene graphs from/to OpenFlight files.
Node Object Image HeightField
Read X
Write X
*/ class FLTReaderWriter : public ReaderWriter { public: FLTReaderWriter() : _implicitPath( "." ) { supportsExtension("flt","OpenFlight format"); supportsOption("clampToEdge","Import option"); supportsOption("keepExternalReferences","Import option"); supportsOption("preserveFace","Import option"); supportsOption("preserveObject","Import option"); supportsOption("replaceDoubleSidedPolys","Import option"); supportsOption("dofAnimation","Import option"); supportsOption("billboardCenter","Import option"); supportsOption("noTextureAlphaForTransparancyBinning","Import option"); supportsOption("readObjectRecordData","Import option"); supportsOption("preserveNonOsgAttrsAsUserData","Import option: If present in the Options string, following OpenFlight specific attributes will be stored as UserValue: surface: , feature: , IRColor: "); supportsOption("noUnitsConversion","Import option"); supportsOption("convertToFeet","Import option"); supportsOption("convertToInches","Import option"); supportsOption("convertToMeters","Import option"); supportsOption("convertToKilometers","Import option"); supportsOption("convertToNauticalMiles","Import option"); supportsOption( "version=", "Export option: Specifies the version of the output OpenFlight file. Supported values include 15.7, 15.8, and 16.1. Default is 16.1. Example: \"version=15.8\"." ); supportsOption( "units=", "Export option: Specifies the contents of the Units field of the OpenFlight header record. Valid values include INCHES, FEET, METERS, KILOMETERS, and NAUTICAL_MILES. Default is METERS. Example: \"units=METERS\"." ); supportsOption( "validate", "Export option: If present in the Options string, the plugin does not write an OpenFlight file. Instead, it returns an indication of the scene graph's suitability for OpenFlight export." ); supportsOption( "tempDir=", "Export option: Specifies the directory to use for creation of temporary files. If not specified, the directory is taken from the file name. If the file doesn't contain a path, the current working directory is used. Applications should set this to the name of their app-specific temp directory. If the path contains spaces, use double quotes to ensure correct parsing. Examples: \"tempDir=/tmp\", \"tempDir=\"C:\\My Temp Dir\"." ); supportsOption( "lighting=", "Export option: Specifies a default enable/disable state for lighting, for Nodes in the exported scene graph that don't set it explicitly. By default, the exporter assumes lighting is enabled (GL_LIGHTING ON). Set this to either ON or OFF. Example: \"lighting=OFF\"." ); supportsOption( "stripTextureFilePath", "Export option: If present in the Options string, the exporter strips the path from texture file names, and writes only the texture file name to the FLT Texture Palette. By default, the exporter doesn't strip the path, and the name written to the Texture Palette is taken directly from the osg::Image object referenced by the osg::Texture2D StateAttribute." ); } virtual const char* className() const { return "FLT Reader/Writer"; } virtual bool acceptsExtension(const std::string& extension) const { return equalCaseInsensitive(extension,"flt") || extension.empty(); } virtual ReadResult readObject(const std::string& file, const Options* options) const { return readNode(file, options); } virtual ReadResult readNode(const std::string& file, const Options* options) const { SERIALIZER(); std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile(file, options); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; // in local cache? { osg::Node* node = flt::Registry::instance()->getExternalFromLocalCache(fileName); if (node) return ReadResult(node, ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); } // setting up the database path so that internally referenced file are searched for on relative paths. osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); ReadResult rr; // read file { osgDB::ifstream istream; istream.imbue(std::locale::classic()); istream.open(fileName.c_str(), std::ios::in | std::ios::binary); if (istream) { rr = readNode(istream,local_opt.get()); } } static int nestedExternalsLevel = 0; if (rr.success()) { // add to local cache. flt::Registry::instance()->addExternalToLocalCache(fileName,rr.getNode()); bool keepExternalReferences = false; if (options) keepExternalReferences = (options->getOptionString().find("keepExternalReferences")!=std::string::npos); if ( !keepExternalReferences ) { OSG_DEBUG << "keepExternalReferences not found, so externals will be re-readed"<accept(visitor); nestedExternalsLevel--; } } else { OSG_DEBUG << "keepExternalReferences found, so externals will be left as ProxyNodes"<clearLocalCache(); return rr; } virtual ReadResult readObject(std::istream& fin, const Options* options) const { return readNode(fin, options); } virtual ReadResult readNode(std::istream& fin, const Options* options) const { Document document; document.setOptions(options); // option string and parent pools if (options) { const char readerMsg[] = "flt reader option: "; document.setReplaceClampWithClampToEdge((options->getOptionString().find("clampToEdge")!=std::string::npos)); OSG_DEBUG << readerMsg << "clampToEdge=" << document.getReplaceClampWithClampToEdge() << std::endl; document.setKeepExternalReferences((options->getOptionString().find("keepExternalReferences")!=std::string::npos)); OSG_DEBUG << readerMsg << "keepExternalReferences=" << document.getKeepExternalReferences() << std::endl; document.setPreserveFace((options->getOptionString().find("preserveFace")!=std::string::npos)); OSG_DEBUG << readerMsg << "preserveFace=" << document.getPreserveFace() << std::endl; document.setPreserveObject((options->getOptionString().find("preserveObject")!=std::string::npos)); OSG_DEBUG << readerMsg << "preserveObject=" << document.getPreserveObject() << std::endl; document.setReplaceDoubleSidedPolys((options->getOptionString().find("replaceDoubleSidedPolys")!=std::string::npos)); OSG_DEBUG << readerMsg << "replaceDoubleSidedPolys=" << document.getReplaceDoubleSidedPolys() << std::endl; document.setDefaultDOFAnimationState((options->getOptionString().find("dofAnimation")!=std::string::npos)); OSG_DEBUG << readerMsg << "dofAnimation=" << document.getDefaultDOFAnimationState() << std::endl; document.setUseBillboardCenter((options->getOptionString().find("billboardCenter")!=std::string::npos)); OSG_DEBUG << readerMsg << "billboardCenter=" << document.getUseBillboardCenter() << std::endl; document.setUseTextureAlphaForTransparancyBinning(options->getOptionString().find("noTextureAlphaForTransparancyBinning")==std::string::npos); OSG_DEBUG << readerMsg << "noTextureAlphaForTransparancyBinning=" << !document.getUseTextureAlphaForTransparancyBinning() << std::endl; document.setReadObjectRecordData(options->getOptionString().find("readObjectRecordData")!=std::string::npos); OSG_DEBUG << readerMsg << "readObjectRecordData=" << document.getReadObjectRecordData() << std::endl; document.setPreserveNonOsgAttrsAsUserData((options->getOptionString().find("preserveNonOsgAttrsAsUserData")!=std::string::npos)); OSG_DEBUG << readerMsg << "preserveNonOsgAttrsAsUserData=" << document.getPreserveNonOsgAttrsAsUserData() << std::endl; document.setDoUnitsConversion((options->getOptionString().find("noUnitsConversion")==std::string::npos)); // default to true, unless noUnitsConversion is specified. OSG_DEBUG << readerMsg << "noUnitsConversion=" << !document.getDoUnitsConversion() << std::endl; if (document.getDoUnitsConversion()) { if (options->getOptionString().find("convertToFeet")!=std::string::npos) document.setDesiredUnits(FEET); else if (options->getOptionString().find("convertToInches")!=std::string::npos) document.setDesiredUnits(INCHES); else if (options->getOptionString().find("convertToMeters")!=std::string::npos) document.setDesiredUnits(METERS); else if (options->getOptionString().find("convertToKilometers")!=std::string::npos) document.setDesiredUnits(KILOMETERS); else if (options->getOptionString().find("convertToNauticalMiles")!=std::string::npos) document.setDesiredUnits(NAUTICAL_MILES); } const ParentPools* pools = dynamic_cast( options->getUserData() ); if (pools) { // This file is an external reference. The individual pools will // be non-NULL if the parent is overriding the ext ref model's pools. if (pools->getColorPool()) document.setColorPool( pools->getColorPool(), true ); if (pools->getTexturePool()) document.setTexturePool( pools->getTexturePool(), true ); if (pools->getMaterialPool()) document.setMaterialPool( pools->getMaterialPool(), true ); if (pools->getLightSourcePool()) document.setLightSourcePool( pools->getLightSourcePool(), true ); if (pools->getLPAppearancePool()) document.setLightPointAppearancePool( pools->getLPAppearancePool(), true ); if (pools->getLPAnimationPool()) document.setLightPointAnimationPool( pools->getLPAnimationPool(), true ); if (pools->getShaderPool()) document.setShaderPool( pools->getShaderPool(), true ); } } const int RECORD_HEADER_SIZE = 4; opcode_type continuationOpcode = INVALID_OP; std::string continuationBuffer; while (fin.good() && !document.done()) { // The continuation record complicates things a bit. // get opcode and size flt::DataInputStream dataStream(fin.rdbuf()); opcode_type opcode = (opcode_type)dataStream.readUInt16(); size_type size = (size_type)dataStream.readUInt16(); // If size == 0, an EOF has probably been reached, i.e. there is nothing // more to read so we must return. if (size==0) { // If a header was read, we return it. // This allows us handle files with empty hierarchies. if (document.getHeaderNode()) { return document.getHeaderNode(); } else // (no valid header) { return ReadResult::ERROR_IN_READING_FILE; } } // variable length record complete? if (!continuationBuffer.empty() && opcode!=CONTINUATION_OP) { // parse variable length record std::stringbuf sb(continuationBuffer); flt::RecordInputStream recordStream(&sb); recordStream.readRecordBody(continuationOpcode, continuationBuffer.length(), document); continuationOpcode = INVALID_OP; continuationBuffer.clear(); } // variable length record use continuation buffer in case next // record is a continuation record. if (opcode==EXTENSION_OP || opcode==NAME_TABLE_OP || opcode==LOCAL_VERTEX_POOL_OP || opcode==MESH_PRIMITIVE_OP) { continuationOpcode = opcode; if (size > RECORD_HEADER_SIZE) { // Put record in buffer. std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0'); fin.read(&buffer[0], size-RECORD_HEADER_SIZE); // Can't parse it until we know we have the complete record. continuationBuffer = buffer; } } else if (opcode==CONTINUATION_OP) { if (size > RECORD_HEADER_SIZE) { std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0'); fin.read(&buffer[0], size-RECORD_HEADER_SIZE); // The record continues. continuationBuffer.append(buffer); } } else if (opcode==VERTEX_PALETTE_OP) { // Vertex Palette needs the file stream as it reads beyond the current record. flt::RecordInputStream recordStream(fin.rdbuf()); recordStream.readRecordBody(opcode, size, document); } else // normal (fixed size) record. { // Put record in buffer. std::string buffer((std::string::size_type)size,'\0'); if (size > RECORD_HEADER_SIZE) fin.read(&buffer[0], size-RECORD_HEADER_SIZE); // Parse buffer. std::stringbuf sb(buffer); flt::RecordInputStream recordStream(&sb); recordStream.readRecordBody(opcode, size, document); } } if (!document.getHeaderNode()) return ReadResult::ERROR_IN_READING_FILE; if (!document.getPreserveFace()) { osgUtil::Optimizer optimizer; optimizer.optimize(document.getHeaderNode(), osgUtil::Optimizer::SHARE_DUPLICATE_STATE | osgUtil::Optimizer::MERGE_GEOMETRY | osgUtil::Optimizer::MERGE_GEODES | osgUtil::Optimizer::TESSELLATE_GEOMETRY | osgUtil::Optimizer::STATIC_OBJECT_DETECTION); } return document.getHeaderNode(); } virtual WriteResult writeObject(const Object& object,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { const Node* node = dynamic_cast(&object); if (node) return writeNode( *node, fileName, options ); return WriteResult::FILE_NOT_HANDLED; } virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const { if ( fileName.empty() ) { return WriteResult::FILE_NOT_HANDLED; } std::string ext = osgDB::getLowerCaseFileExtension( fileName ); if ( !acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED; // Get and save the implicit path name (in case a path wasn't specified in Options). std::string filePath = osgDB::getFilePath( fileName ); if (!filePath.empty()) _implicitPath = filePath; osgDB::ofstream fOut; fOut.open( fileName.c_str(), std::ios::out | std::ios::binary ); if ( fOut.fail()) { OSG_FATAL << "fltexp: Failed to open output stream." << std::endl; return WriteResult::ERROR_IN_WRITING_FILE; } WriteResult wr = WriteResult::FILE_NOT_HANDLED; wr = writeNode( node, fOut, options ); fOut.close(); return wr; } virtual WriteResult writeObject(const Object& object,std::ostream& fout, const osgDB::ReaderWriter::Options* options) const { const Node* node = dynamic_cast(&object); if (node) return writeNode( *node, fout, options ); return WriteResult::FILE_NOT_HANDLED; } virtual WriteResult writeNode( const osg::Node& node, std::ostream& fOut, const Options* options ) const { // Convert Options to FltOptions. ExportOptions* fltOpt = new ExportOptions( options ); fltOpt->parseOptionsString(); // If user didn't specify a temp dir, use the output directory // that was implicit in the output file name. if (fltOpt->getTempDir().empty()) fltOpt->setTempDir( _implicitPath ); if (!fltOpt->getTempDir().empty()) { // If the temp directory doesn't already exist, make it. if ( !osgDB::makeDirectory( fltOpt->getTempDir() ) ) { OSG_FATAL << "fltexp: Error creating temp dir: " << fltOpt->getTempDir() << std::endl; return WriteResult::ERROR_IN_WRITING_FILE; } } flt::DataOutputStream dos( fOut.rdbuf(), fltOpt->getValidateOnly() ); flt::FltExportVisitor fnv( &dos, fltOpt ); // Hm. 'node' is const, but in order to write out this scene graph, // must use Node::accept() which requires 'node' to be non-const. // Pretty much requires casting away const. osg::Node* nodeNonConst = const_cast( &node ); if (!nodeNonConst) return WriteResult::ERROR_IN_WRITING_FILE; nodeNonConst->accept( fnv ); fnv.complete( node ); return fltOpt->getWriteResult(); } protected: mutable std::string _implicitPath; mutable OpenThreads::ReentrantMutex _serializerMutex; }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(OpenFlight, FLTReaderWriter) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/FltExportVisitor.h0000644000175000017500000002077013151044751027530 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_FLT_EXPORT_VISITOR_H__ #define __FLTEXP_FLT_EXPORT_VISITOR_H__ 1 #include #include "ExportOptions.h" #include "Types.h" #include #include #include namespace osg { class DrawArrays; class DrawArrayLengths; class DrawElements; class Geometry; class StateSet; class Switch; class Material; class Texture2D; } namespace osgSim { class DOFTransform; class MultiSwitch; class LightPointNode; class ObjectRecordData; } namespace flt { class ExportOptions; class DataOutputStream; class MaterialPaletteManager; class TexturePaletteManager; class VertexPaletteManager; class LightSourcePaletteManager; /*! The main NodeVisitor for walking the scene graph during export. A collection of apply() methods is in FltExportVisitor.cpp. The apply() methods call several other methods for writing specific FLT record types, most of which are in exp*.cpp. */ class FltExportVisitor : public osg::NodeVisitor { public: FltExportVisitor( DataOutputStream* dos, ExportOptions* fltOpt ); ~FltExportVisitor( ); bool complete( const osg::Node& node ); virtual void apply( osg::Group& node ); virtual void apply( osg::Sequence& node ); virtual void apply( osg::Switch& node ); virtual void apply( osg::LOD& node ); virtual void apply( osg::MatrixTransform& node ); virtual void apply( osg::PositionAttitudeTransform& node ); virtual void apply( osg::Transform& node ); virtual void apply( osg::LightSource& node ); virtual void apply( osg::Geode& node ); virtual void apply( osg::Node& node ); virtual void apply( osg::ProxyNode& node ); // Primary records void writeHeader( const std::string& headerName ); void writeGroup( const osg::Group& node ); void writeGroup( const osg::Group& group, int32 flags, int32 loopCount, float32 loopDuration, float32 lastFrameDuration); void writeSequence( const osg::Sequence& node ); void writeObject( const osg::Group& node, osgSim::ObjectRecordData* ord ); void writeDegreeOfFreedom( const osgSim::DOFTransform* dof ); void writeExternalReference( const osg::ProxyNode& node ); void writeLevelOfDetail( const osg::LOD& lod, const osg::Vec3d& center, double switchInDist, double switchOutDist); void writeLightSource( const osg::LightSource& ls ); void writeSwitch( const osgSim::MultiSwitch* ms ); void writeSwitch( const osg::Switch* ms ); void writeLightPoint( const osgSim::LightPointNode* lpn ); // Ancillary records void writeComment( const osg::Node& node, DataOutputStream* dos=NULL ); void writeLongID( const std::string& id, DataOutputStream* dos=NULL ); void writeMatrix( const osg::Referenced* ref ); void writeContinuationRecord( const unsigned short length ); // Control records void writePush(); void writePop(); void writePushSubface(); void writePopSubface(); // Helper routine for traversing a pushed subtree void writePushTraverseWritePop(osg::Node& node) { writePush(); traverse(node); writePop(); } void writePushTraverseChildWritePop(osg::Node& node) { writePush(); node.accept(*this); writePop(); } // Geometry records void writeFace( const osg::Geode& geode, const osg::Geometry& geom, GLenum mode ); void writeMesh( const osg::Geode& geode, const osg::Geometry& geom ); int writeVertexList( int first, unsigned int count ); int writeVertexList( const std::vector& indices, unsigned int count ); void writeMeshPrimitive( const std::vector& indices, GLenum mode ); void writeLocalVertexPool( const osg::Geometry& geom ); void writeMultitexture( const osg::Geometry& geom ); void writeUVList( int numVerts, const osg::Geometry& geom, const std::vector& indices ); void writeUVList( int numVerts, const osg::Geometry& geom, unsigned int first=0); // Light Point records void writeLightPoint(); // Exporter doesn't currently support color palette; write a dummy in its place to // support loaders that require it. void writeColorPalette(); // StateSet stack support void pushStateSet( const osg::StateSet* rhs ); void popStateSet(); const osg::StateSet* getCurrentStateSet() const; void clearStateSetStack(); // Write a .attr file if none exists in the data file path. void writeATTRFile( int unit, const osg::Texture2D* texture ) const; private: // Methods for handling different primitive set types. // These are defined in expGeometryRecords.cpp. void handleDrawArrays( const osg::DrawArrays* da, const osg::Geometry& geom, const osg::Geode& geode ); void handleDrawArrayLengths( const osg::DrawArrayLengths* dal, const osg::Geometry& geom, const osg::Geode& geode ); void handleDrawElements( const osg::DrawElements* de, const osg::Geometry& geom, const osg::Geode& geode ); bool isLit( const osg::Geometry& geom ) const; bool isTextured( int unit, const osg::Geometry& geom ) const; bool isMesh( const GLenum mode ) const; bool atLeastOneFace( const osg::Geometry& geom ) const; bool atLeastOneMesh( const osg::Geometry& geom ) const; osg::ref_ptr< ExportOptions > _fltOpt; // _dos is the primary output stream, produces the actual .flt file. DataOutputStream& _dos; // _records is a temp file for most records. After the Header and palette // records are written to _dos, _records is copied onto _dos. osgDB::ofstream _recordsStr; DataOutputStream* _records; std::string _recordsTempName; // Track state changes during a scene graph walk. typedef std::vector< osg::ref_ptr > StateSetStack; StateSetStack _stateSetStack; std::auto_ptr _materialPalette; std::auto_ptr _texturePalette; std::auto_ptr _lightSourcePalette; std::auto_ptr _vertexPalette; // Used to avoid duplicate Header/Group records at top of output FLT file. bool _firstNode; }; /*! Helper class to ensure symmetrical state push/pop behavior. */ class ScopedStatePushPop { public: ScopedStatePushPop ( FltExportVisitor * fnv, const osg::StateSet *ss ) : fnv_( fnv ) { fnv_->pushStateSet( ss ); } virtual ~ScopedStatePushPop () { fnv_->popStateSet(); } private: FltExportVisitor * fnv_; }; /*! Automatically handles writing the LongID ancillary record. */ struct IdHelper { IdHelper(flt::FltExportVisitor& v, const std::string& id) : v_(v), id_(id), dos_(NULL) { } // Write an ancillary ID record upon destruction if name is too long ~IdHelper() { if (id_.length() > 8) v_.writeLongID(id_,dos_); } // Allow implicit conversion to the abbreviated name string operator const std::string() const { return( (id_.length() > 8) ? id_.substr(0, 8) : id_ ); } flt::FltExportVisitor& v_; const std::string id_; DataOutputStream* dos_; protected: IdHelper& operator = (const IdHelper&) { return *this; } }; /*! Supports wrapping subfaces with push/pop records. */ struct SubfaceHelper { SubfaceHelper(flt::FltExportVisitor& v, const osg::StateSet* ss ) : v_(v) { _polygonOffsetOn = ( ss->getMode( GL_POLYGON_OFFSET_FILL ) == osg::StateAttribute::ON ); if (_polygonOffsetOn) v_.writePushSubface(); } ~SubfaceHelper() { if (_polygonOffsetOn) v_.writePopSubface(); } flt::FltExportVisitor& v_; bool _polygonOffsetOn; protected: SubfaceHelper& operator = (const SubfaceHelper&) { return *this; } }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/VertexPaletteManager.h0000644000175000017500000000634513151044751030312 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #ifndef __FLTEXP_VERTEX_PALETTE_MANAGER_H__ #define __FLTEXP_VERTEX_PALETTE_MANAGER_H__ 1 #include "DataOutputStream.h" #include "ExportOptions.h" #include #include #include namespace osg { class Geometry; } namespace flt { /*! Manages writing the Vertex Palette record during export. Maintains a map to ensure that instanced VertexArray data is only written once to the palette. Writes the palette record to a temp file and copies it to FltExportVisitor::_dos after the scene graph has been completely walked. */ class VertexPaletteManager { public: VertexPaletteManager( const ExportOptions& fltOpt ); ~VertexPaletteManager(); void add( const osg::Geometry& geom ); void add( const osg::Array* key, const osg::Vec3dArray* v, const osg::Vec4Array* c, const osg::Vec3Array* n, const osg::Vec2Array* t, bool colorPerVertex, bool normalPerVertex, bool allowSharing=true ); unsigned int byteOffset( unsigned int idx ) const; void write( DataOutputStream& dos ) const; /*! Static utility routines for handling the morass of array types that could be found in a Geometry object's vertex/ normal/texcoord/color data. */ static osg::ref_ptr< const osg::Vec2Array > asVec2Array( const osg::Array* in, const unsigned int n ); static osg::ref_ptr< const osg::Vec3Array > asVec3Array( const osg::Array* in, const unsigned int n ); static osg::ref_ptr< const osg::Vec3dArray > asVec3dArray( const osg::Array* in, const unsigned int n ); static osg::ref_ptr< const osg::Vec4Array > asVec4Array( const osg::Array* in, const unsigned int n ); protected: typedef enum { VERTEX_C, VERTEX_CN, VERTEX_CNT, VERTEX_CT } PaletteRecordType; static PaletteRecordType recordType( const osg::Array* v, const osg::Array* c, const osg::Array* n, const osg::Array* t ); unsigned int recordSize( PaletteRecordType recType ); void writeRecords( const osg::Vec3dArray* v, const osg::Vec4Array* c, const osg::Vec3Array* n, const osg::Vec2Array* t, bool colorPerVertex, bool normalPerVertex ); unsigned int _currentSizeBytes; struct ArrayInfo { ArrayInfo(); unsigned int _byteStart; unsigned int _idxSizeBytes; unsigned int _idxCount; }; ArrayInfo* _current; ArrayInfo _nonShared; typedef std::map< const osg::Array*, ArrayInfo > ArrayMap; ArrayMap _arrayMap; mutable osgDB::ofstream _verticesStr; DataOutputStream* _vertices; std::string _verticesTempName; const ExportOptions& _fltOpt; }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/expGeometryRecords.cpp0000644000175000017500000010543013151044751030403 0ustar albertoalberto/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "FltExportVisitor.h" #include "DataOutputStream.h" #include "Opcodes.h" #include "MaterialPaletteManager.h" #include "TexturePaletteManager.h" #include "VertexPaletteManager.h" #include #include #include #include #include #include #include #include #include namespace flt { // Bit flags for multitexturing static unsigned int LAYER_1( 0x80000000 >> 0 ); #if 0 // unused so if'deffing out static unsigned int LAYER_2( 0x80000000 >> 1 ); static unsigned int LAYER_3( 0x80000000 >> 2 ); static unsigned int LAYER_4( 0x80000000 >> 3 ); static unsigned int LAYER_5( 0x80000000 >> 4 ); static unsigned int LAYER_6( 0x80000000 >> 5 ); static unsigned int LAYER_7( 0x80000000 >> 6 ); #endif bool FltExportVisitor::isLit( const osg::Geometry& geom ) const { const osg::StateSet* ss = getCurrentStateSet(); if ( ss->getMode( GL_LIGHTING ) & osg::StateAttribute::ON ) return true; else return false; //( geom.getNormalBinding() == osg::Array::BIND_PER_VERTEX ); } bool FltExportVisitor::isTextured( int unit, const osg::Geometry& geom ) const { const osg::StateSet* ss = getCurrentStateSet(); bool texOn( ss->getTextureMode( unit, GL_TEXTURE_2D ) & osg::StateAttribute::ON ); bool hasCoords( geom.getTexCoordArray( unit ) != NULL ); return( texOn && hasCoords ); } bool FltExportVisitor::isMesh( const GLenum mode ) const { return( (mode == GL_TRIANGLE_STRIP) || (mode == GL_TRIANGLE_FAN) || (mode == GL_QUAD_STRIP) ); } bool FltExportVisitor::atLeastOneFace( const osg::Geometry& geom ) const { // Return true if at least one PrimitiveSet mode will use a Face record. unsigned int jdx; for (jdx=0; jdx < geom.getNumPrimitiveSets(); jdx++) { const osg::PrimitiveSet* prim = geom.getPrimitiveSet( jdx ); if( !isMesh( prim->getMode() ) ) return true; } // All PrimitiveSet modes will use Mesh records. return false; } bool FltExportVisitor::atLeastOneMesh( const osg::Geometry& geom ) const { // Return true if at least one PrimitiveSet mode will use a Mesh record. unsigned int jdx; for (jdx=0; jdx < geom.getNumPrimitiveSets(); jdx++) { const osg::PrimitiveSet* prim = geom.getPrimitiveSet( jdx ); if( isMesh( prim->getMode() ) ) return true; } // All PrimitiveSet modes will use Face records. return false; } void FltExportVisitor::writeFace( const osg::Geode& geode, const osg::Geometry& geom, GLenum mode ) { enum DrawMode { SOLID_BACKFACE = 0, SOLID_NO_BACKFACE = 1, WIREFRAME_CLOSED = 2, WIREFRAME_NOT_CLOSED = 3, SURROUND_ALTERNATE_COLOR = 4, OMNIDIRECTIONAL_LIGHT = 8, UNIDIRECTIONAL_LIGHT = 9, BIDIRECTIONAL_LIGHT = 10 }; enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; // const unsigned int TERRAIN_BIT = 0x80000000u >> 0; // const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; // const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; // const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout const unsigned int HIDDEN_BIT = 0x80000000u >> 5; // const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; uint32 flags( PACKED_COLOR_BIT ); if (geode.getNodeMask() == 0) flags |= HIDDEN_BIT; osg::StateSet const* ss = getCurrentStateSet(); enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; int8 lightMode; osg::Vec4 packedColorRaw( 1., 1., 1., 1. ); uint16 transparency( 0 ); if (osg::getBinding(geom.getColorArray()) == osg::Array::BIND_PER_VERTEX) { if( isLit( geom ) ) lightMode = VERTEX_COLOR_LIGHTING; else lightMode = VERTEX_COLOR; } else { const osg::Vec4Array* c = dynamic_cast( geom.getColorArray() ); if (c && (c->size() > 0)) { packedColorRaw = (*c)[0]; transparency = uint16((1. - packedColorRaw[3]) * (double)0xffff); } if ( isLit( geom ) ) lightMode = FACE_COLOR_LIGHTING; else lightMode = FACE_COLOR; } uint32 packedColor; packedColor = (int)(packedColorRaw[3]*255) << 24 | (int)(packedColorRaw[2]*255) << 16 | (int)(packedColorRaw[1]*255) << 8 | (int)(packedColorRaw[0]*255); int8 drawType = SOLID_NO_BACKFACE; switch( mode ) { case GL_POINTS: { std::string warning( "fltexp: GL_POINTS not supported in FLT export." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; break; } case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_QUAD_STRIP: { std::string warning( "fltexp: Wrong mode in Face record." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; break; } case GL_LINES: case GL_LINE_STRIP: drawType = WIREFRAME_NOT_CLOSED; break; case GL_LINE_LOOP: drawType = WIREFRAME_CLOSED; break; case GL_TRIANGLES: case GL_QUADS: case GL_POLYGON: { // Default to no facet culling drawType = SOLID_NO_BACKFACE; // If facet-culling isn't *dis*abled, check whether the CullFace mode is BACK if (ss->getMode(GL_CULL_FACE) & osg::StateAttribute::ON) { osg::CullFace const* cullFace = static_cast( ss->getAttribute(osg::StateAttribute::CULLFACE) ); if( cullFace->getMode() == osg::CullFace::BACK ) drawType = SOLID_BACKFACE; // Note: OpenFlt can't handle FRONT or FRONT_AND_BACK settings, so ignore these(??) } break; } } // Determine the material properties for the face int16 materialIndex( -1 ); if (isLit( geom )) { osg::Material const* currMaterial = static_cast( ss->getAttribute(osg::StateAttribute::MATERIAL) ); materialIndex = _materialPalette->add(currMaterial); } // Get base texture int16 textureIndex( -1 ); if (isTextured( 0, geom )) { const osg::Texture2D* texture = static_cast( ss->getTextureAttribute( 0, osg::StateAttribute::TEXTURE ) ); if (texture != NULL) textureIndex = _texturePalette->add( 0, texture ); else { std::string warning( "fltexp: Face is textured, but Texture2D StateAttribute is NULL." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); } } // Set the appropriate template mode based // on blending or Billboarding. TemplateMode templateMode( FIXED_NO_ALPHA_BLENDING ); const osg::Billboard* bb = dynamic_cast< const osg::Billboard* >( &geode ); if (bb != NULL) { if( bb->getMode() == osg::Billboard::AXIAL_ROT ) templateMode = AXIAL_ROTATE_WITH_ALPHA_BLENDING; else templateMode = POINT_ROTATE_WITH_ALPHA_BLENDING; } else if ( ss->getMode( GL_BLEND ) & osg::StateAttribute::ON ) { const osg::BlendFunc* bf = static_cast( ss->getAttribute(osg::StateAttribute::BLENDFUNC) ); if( (bf->getSource() == osg::BlendFunc::SRC_ALPHA) && (bf->getDestination() == osg::BlendFunc::ONE_MINUS_SRC_ALPHA) ) templateMode = FIXED_ALPHA_BLENDING; } uint16 length( 80 ); IdHelper id( *this, geode.getName() ); _records->writeInt16( (int16) FACE_OP ); _records->writeUInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // IR color code _records->writeInt16( 0 ); // Relative priority _records->writeInt8( drawType ); // Draw type _records->writeInt8( 0 ); // Texture white _records->writeInt16( -1 ); // Color name index _records->writeInt16( -1 ); // Alternate color name index _records->writeInt8( 0 ); // Reserved _records->writeInt8( templateMode ); // Template (billboard) _records->writeInt16( -1 ); // Detail texture pattern index _records->writeInt16( textureIndex ); // Texture pattern index _records->writeInt16( materialIndex ); // Material index _records->writeInt16( 0 ); // Surface material code _records->writeInt16( 0 ); // Feature ID _records->writeInt32( 0 ); // IR material code _records->writeUInt16( transparency ); // Transparency _records->writeInt8( 0 ); // LOD generation control _records->writeInt8( 0 ); // Line style index _records->writeUInt32( flags ); // Flags _records->writeInt8( lightMode ); // Light mode _records->writeFill( 7 ); // Reserved _records->writeUInt32( packedColor ); // Packed color, primary _records->writeUInt32( 0x00ffffff ); // Packed color, alternate _records->writeInt16( -1 ); // Texture mapping index _records->writeInt16( 0 ); // Reserved _records->writeInt32( -1 ); // Primary color index _records->writeInt32( -1 ); // Alternate color index // Next four bytes: // 15.8: two 2-byte "reserved" fields // 15.9: one 4-byte "reserved" field; _records->writeInt16( 0 ); // Reserved _records->writeInt16( -1 ); // Shader index } void FltExportVisitor::writeMesh( const osg::Geode& geode, const osg::Geometry& geom ) { enum DrawMode { SOLID_BACKFACE = 0, SOLID_NO_BACKFACE = 1, WIREFRAME_CLOSED = 2, WIREFRAME_NOT_CLOSED = 3, SURROUND_ALTERNATE_COLOR = 4, OMNIDIRECTIONAL_LIGHT = 8, UNIDIRECTIONAL_LIGHT = 9, BIDIRECTIONAL_LIGHT = 10 }; enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; // const unsigned int TERRAIN_BIT = 0x80000000u >> 0; //const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; //const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; //const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout const unsigned int HIDDEN_BIT = 0x80000000u >> 5; //const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; uint32 flags( PACKED_COLOR_BIT ); if (geode.getNodeMask() == 0) flags |= HIDDEN_BIT; enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; int8 lightMode; osg::Vec4 packedColorRaw( 1., 1., 1., 1. ); uint16 transparency( 0 ); if (osg::getBinding(geom.getColorArray()) == osg::Array::BIND_PER_VERTEX) { if (isLit( geom )) lightMode = VERTEX_COLOR_LIGHTING; else lightMode = VERTEX_COLOR; } else { const osg::Vec4Array* c = dynamic_cast( geom.getColorArray() ); if (c && (c->size() > 0)) { packedColorRaw = (*c)[0]; transparency = uint16((1. - packedColorRaw[3]) * (double)0xffff); } if (isLit( geom )) lightMode = FACE_COLOR_LIGHTING; else lightMode = FACE_COLOR; } uint32 packedColor; packedColor = (int)(packedColorRaw[3]*255) << 24 | (int)(packedColorRaw[2]*255) << 16 | (int)(packedColorRaw[1]*255) << 8 | (int)(packedColorRaw[0]*255); int8 drawType; osg::StateSet const* ss = getCurrentStateSet(); { // Default to no facet culling drawType = SOLID_NO_BACKFACE; // If facet-culling isn't *dis*abled, check whether the CullFace mode is BACK if (ss->getMode(GL_CULL_FACE) & osg::StateAttribute::ON) { osg::CullFace const* cullFace = static_cast( ss->getAttribute(osg::StateAttribute::CULLFACE) ); if( cullFace->getMode() == osg::CullFace::BACK ) drawType = SOLID_BACKFACE; // Note: OpenFlt can't handle FRONT or FRONT_AND_BACK settings, so ignore these(??) } } // Determine the material properties for the face int16 materialIndex( -1 ); if (isLit( geom )) { osg::Material const* currMaterial = static_cast( ss->getAttribute(osg::StateAttribute::MATERIAL) ); materialIndex = _materialPalette->add(currMaterial); } // Get base texture int16 textureIndex( -1 ); if (isTextured( 0, geom )) { const osg::Texture2D* texture = static_cast( ss->getTextureAttribute( 0, osg::StateAttribute::TEXTURE ) ); if (texture != NULL) textureIndex = _texturePalette->add( 0, texture ); else { std::string warning( "fltexp: Mesh is textured, but Texture2D StateAttribute is NULL." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); } } // Set the appropriate template mode based // on blending or Billboarding. TemplateMode templateMode( FIXED_NO_ALPHA_BLENDING ); const osg::Billboard* bb = dynamic_cast< const osg::Billboard* >( &geode ); if (bb != NULL) { if( bb->getMode() == osg::Billboard::AXIAL_ROT ) templateMode = AXIAL_ROTATE_WITH_ALPHA_BLENDING; else templateMode = POINT_ROTATE_WITH_ALPHA_BLENDING; } else if ( ss->getMode( GL_BLEND ) & osg::StateAttribute::ON ) { const osg::BlendFunc* bf = static_cast( ss->getAttribute(osg::StateAttribute::BLENDFUNC) ); if( (bf->getSource() == osg::BlendFunc::SRC_ALPHA) && (bf->getDestination() == osg::BlendFunc::ONE_MINUS_SRC_ALPHA) ) templateMode = FIXED_ALPHA_BLENDING; } uint16 length( 84 ); IdHelper id( *this, geode.getName() ); _records->writeInt16( (int16) MESH_OP ); _records->writeUInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // Reserved _records->writeInt32( 0 ); // IR color code _records->writeInt16( 0 ); // Relative priority _records->writeInt8( drawType ); // Draw type _records->writeInt8( 0 ); // Texture white _records->writeInt16( -1 ); // Color name index _records->writeInt16( -1 ); // Alternate color name index _records->writeInt8( 0 ); // Reserved _records->writeInt8( templateMode ); // Template (billboard) _records->writeInt16( -1 ); // Detail texture pattern index _records->writeInt16( textureIndex ); // Texture pattern index _records->writeInt16( materialIndex ); // Material index _records->writeInt16( 0 ); // Surface material code _records->writeInt16( 0 ); // Feature ID _records->writeInt32( 0 ); // IR material code _records->writeUInt16( transparency ); // Transparency _records->writeInt8( 0 ); // LOD generation control _records->writeInt8( 0 ); // Line style index _records->writeUInt32( flags ); // Flags _records->writeInt8( lightMode ); // Light mode _records->writeFill( 7 ); // Reserved _records->writeUInt32( packedColor ); // Packed color, primary _records->writeUInt32( 0x00ffffff ); // Packed color, alternate _records->writeInt16( -1 ); // Texture mapping index _records->writeInt16( 0 ); // Reserved _records->writeInt32( -1 ); // Primary color index _records->writeInt32( -1 ); // Alternate color index // Next four bytes: // 15.8: two 2-byte "reserved" fields // 15.9: one 4-byte "reserved" field _records->writeInt16( 0 ); // Reserved _records->writeInt16( -1 ); // Shader index } int FltExportVisitor::writeVertexList( int first, unsigned int count ) { _records->writeInt16( (int16) VERTEX_LIST_OP ); _records->writeUInt16( 4 + (count*4) ); unsigned int idx; for( idx=0; idxwriteInt32( _vertexPalette->byteOffset( first+idx ) ); return count; } int FltExportVisitor::writeVertexList( const std::vector& indices, unsigned int count ) { _records->writeInt16( (int16) VERTEX_LIST_OP ); _records->writeUInt16( 4 + (count*4) ); unsigned int idx; for( idx=0; idxwriteInt32( _vertexPalette->byteOffset( indices[ idx ] ) ); return count; } void FltExportVisitor::writeMeshPrimitive( const std::vector& indices, GLenum mode ) { int16 primType; switch( mode ) { case GL_TRIANGLE_STRIP: primType = 1; break; case GL_TRIANGLE_FAN: primType = 2; break; case GL_QUAD_STRIP: primType = 3; break; default: // Warning should already be recorded. Do nothing. return; break; } uint16 length( 12 + (4 * indices.size()) ); _records->writeInt16( (int16) MESH_PRIMITIVE_OP ); _records->writeUInt16( length ); _records->writeInt16( primType ); // primitive type _records->writeInt16( 4 ); // index size, 4 bytes _records->writeInt32( indices.size() ); // vertex count std::vector::const_iterator it = indices.begin(); while (it != indices.end()) { _records->writeUInt32( (*it) ); it++; } } void FltExportVisitor::writeLocalVertexPool( const osg::Geometry& geom ) { // Attribute Mask static const unsigned int HAS_POSITION = 0x80000000u >> 0; // static const unsigned int HAS_COLOR_INDEX = 0x80000000u >> 1; static const unsigned int HAS_RGBA_COLOR = 0x80000000u >> 2; static const unsigned int HAS_NORMAL = 0x80000000u >> 3; static const unsigned int HAS_BASE_UV = 0x80000000u >> 4; static const unsigned int HAS_UV_LAYER1 = 0x80000000u >> 5; static const unsigned int HAS_UV_LAYER2 = 0x80000000u >> 6; static const unsigned int HAS_UV_LAYER3 = 0x80000000u >> 7; static const unsigned int HAS_UV_LAYER4 = 0x80000000u >> 8; static const unsigned int HAS_UV_LAYER5 = 0x80000000u >> 9; static const unsigned int HAS_UV_LAYER6 = 0x80000000u >> 10; static const unsigned int HAS_UV_LAYER7 = 0x80000000u >> 11; const osg::Array* v = geom.getVertexArray(); uint32 numVerts( v->getNumElements() ); osg::ref_ptr< const osg::Vec3dArray > v3 = VertexPaletteManager::asVec3dArray( v, numVerts ); if (!v3) { std::string warning( "fltexp: writeLocalVertexPool: VertexArray is not Vec3Array." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } // Compute attribute bits and vertex size. const osg::Array* c = geom.getColorArray(); const osg::Array* n = geom.getNormalArray(); const osg::Array* t = geom.getTexCoordArray( 0 ); osg::ref_ptr< const osg::Vec4Array > c4 = VertexPaletteManager::asVec4Array( c, numVerts ); osg::ref_ptr< const osg::Vec3Array > n3 = VertexPaletteManager::asVec3Array( n, numVerts ); osg::ref_ptr< const osg::Vec2Array > t2 = VertexPaletteManager::asVec2Array( t, numVerts ); if (c && !c4) return; if (n && !n3) return; if (t && !t2) return; std::vector< osg::ref_ptr< const osg::Vec2Array > > mtc; mtc.resize( 8 ); int unit=1; for( ;unit<8; unit++) mtc[ unit ] = VertexPaletteManager::asVec2Array( geom.getTexCoordArray( unit ), numVerts ); uint32 attr( HAS_POSITION ); unsigned int vertSize( sizeof( float64 ) * 3 ); if ( ( c4 != NULL ) && ( osg::getBinding(geom.getColorArray()) == osg::Array::BIND_PER_VERTEX) ) { attr |= HAS_RGBA_COLOR; vertSize += sizeof( unsigned int ); } if ( ( n3 != NULL ) && ( osg::getBinding(geom.getNormalArray()) == osg::Array::BIND_PER_VERTEX) ) { attr |= HAS_NORMAL; vertSize += ( sizeof( float32 ) * 3 ); } if ( t2 != NULL ) { attr |= HAS_BASE_UV; vertSize += ( sizeof( float32 ) * 2 ); } // Add multitex if (isTextured( 1, geom )) { attr |= HAS_UV_LAYER1; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 2, geom )) { attr |= HAS_UV_LAYER2; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 3, geom )) { attr |= HAS_UV_LAYER3; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 4, geom )) { attr |= HAS_UV_LAYER4; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 5, geom )) { attr |= HAS_UV_LAYER5; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 6, geom )) { attr |= HAS_UV_LAYER6; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 7, geom )) { attr |= HAS_UV_LAYER7; vertSize += ( sizeof( float32 ) * 2 ); } unsigned int maxVerts = (0xffff - 12) / vertSize; unsigned int thisVertCount = (maxVerts > numVerts) ? numVerts : maxVerts; unsigned int currentIndexLimit = maxVerts; uint16 length( 12 + (vertSize * thisVertCount) ); _records->writeInt16( (int16) LOCAL_VERTEX_POOL_OP ); _records->writeUInt16( length ); _records->writeUInt32( numVerts ); // number of vertices _records->writeUInt32( attr ); // attribute bits unsigned int idx; for( idx=0; idxwriteVec3d( (*v3)[ idx ] ); if (attr & HAS_RGBA_COLOR) { osg::Vec4 color = (*c4)[ idx ]; unsigned int packedColor = (int)(color[3]*255) << 24 | (int)(color[2]*255) << 16 | (int)(color[1]*255) << 8 | (int)(color[0]*255); _records->writeUInt32( packedColor ); } if (attr & HAS_NORMAL) _records->writeVec3f( (*n3)[ idx ] ); if (attr & HAS_BASE_UV) _records->writeVec2f( (*t2)[ idx ] ); if (attr & HAS_UV_LAYER1) _records->writeVec2f( (*mtc[1])[ idx ] ); if (attr & HAS_UV_LAYER2) _records->writeVec2f( (*mtc[2])[ idx ] ); if (attr & HAS_UV_LAYER3) _records->writeVec2f( (*mtc[3])[ idx ] ); if (attr & HAS_UV_LAYER4) _records->writeVec2f( (*mtc[4])[ idx ] ); if (attr & HAS_UV_LAYER5) _records->writeVec2f( (*mtc[5])[ idx ] ); if (attr & HAS_UV_LAYER6) _records->writeVec2f( (*mtc[6])[ idx ] ); if (attr & HAS_UV_LAYER7) _records->writeVec2f( (*mtc[7])[ idx ] ); // Handle continuation record if necessary. if ( (idx+1 == currentIndexLimit) && (idx+1 < numVerts) ) { currentIndexLimit += maxVerts; unsigned int remaining( numVerts - (idx+1) ); thisVertCount = (maxVerts > remaining) ? remaining : maxVerts; writeContinuationRecord( (vertSize * thisVertCount) ); } } } void FltExportVisitor::writeMultitexture( const osg::Geometry& geom ) { unsigned int numLayers( 0 ); uint32 flags( 0 ); unsigned int idx; for( idx=1; idx<8; idx++) { if( isTextured( idx, geom ) ) { flags |= LAYER_1 >> (idx-1); numLayers++; } } if( numLayers == 0 ) return; uint16 length( 8 + (8*numLayers) ); _records->writeInt16( (int16) MULTITEXTURE_OP ); _records->writeUInt16( length ); _records->writeInt32( flags ); const osg::StateSet* ss = getCurrentStateSet(); for( idx=1; idx<8; idx++) { if( isTextured( idx, geom ) ) { int16 textureIndex( -1 ); const osg::Texture2D* texture = static_cast( ss->getTextureAttribute( idx, osg::StateAttribute::TEXTURE ) ); if (texture != NULL) textureIndex = _texturePalette->add( idx, texture ); else { std::ostringstream warning; warning << "fltexp: No Texture2D for unit " << idx; OSG_WARN << warning.str() << std::endl; _fltOpt->getWriteResult().warn( warning.str() ); } // texture index (this value is an unsigned int, but has a -1 default per oflt spec: ugh) _records->writeUInt16( static_cast< uint16 >( textureIndex ) ); _records->writeUInt16( 0 ); // TBD effect // mapping index (this value is an unsigned int, but has a -1 default per oflt spec: ugh) _records->writeUInt16( static_cast< uint16 >( -1 ) ); _records->writeUInt16( 0 ); // data } } } void FltExportVisitor::writeUVList( int numVerts, const osg::Geometry& geom, const std::vector& indices ) { unsigned int numLayers( 0 ); uint32 flags( 0 ); unsigned int idx; for( idx=1; idx<8; idx++) { if( isTextured( idx, geom ) ) { flags |= LAYER_1 >> (idx-1); numLayers++; } } if( numLayers == 0 ) return; uint16 length( 8 + (8*numLayers*numVerts) ); _records->writeInt16( (int16) UV_LIST_OP ); _records->writeUInt16( length ); _records->writeInt32( flags ); osg::Vec2 defaultCoord( 0., 0. ); // const osg::StateSet* ss = getCurrentStateSet(); for( int vertexIdx=0; vertexIdx( geom.getTexCoordArray( idx ) ); osg::ref_ptr t2 = dynamic_cast( t ); if (!t2.valid()) { std::ostringstream warning; warning << "fltexp: No Texture2D for unit " << idx; OSG_WARN << warning.str() << std::endl; _fltOpt->getWriteResult().warn( warning.str() ); t2 = new osg::Vec2Array; } const int size = t2->getNumElements(); int vIdx = indices[ vertexIdx ]; osg::Vec2& tc( defaultCoord ); if (vIdx < size) tc = ( *t2 )[ vIdx ]; _records->writeFloat32( tc[ 0 ] ); _records->writeFloat32( tc[ 1 ] ); } } } } void FltExportVisitor::writeUVList( int numVerts, const osg::Geometry& geom, unsigned int first ) { unsigned int numLayers( 0 ); uint32 flags( 0 ); unsigned int idx; for( idx=1; idx<8; idx++) { if( isTextured( idx, geom ) ) { flags |= LAYER_1 >> (idx-1); numLayers++; } } if( numLayers == 0 ) return; uint16 length( 8 + (8*numLayers*numVerts) ); _records->writeInt16( (int16) UV_LIST_OP ); _records->writeUInt16( length ); _records->writeInt32( flags ); osg::Vec2 defaultCoord( 0., 0. ); for( int vertexIdx=0; vertexIdx( geom.getTexCoordArray( idx ) ); osg::ref_ptr t2 = dynamic_cast( t ); if (!t2.valid()) { std::ostringstream warning; warning << "fltexp: No Texture2D for unit " << idx; osg::notify( osg::WARN ) << warning.str() << std::endl; _fltOpt->getWriteResult().warn( warning.str() ); t2 = new osg::Vec2Array; } else if (t2->getNumElements() < first + numVerts) { std::ostringstream warning; warning << "fltexp: Invalid number of texture coordinates for unit " << idx; OSG_WARN << warning.str() << std::endl; _fltOpt->getWriteResult().warn( warning.str() ); } const int size = t2->getNumElements(); int vIdx = first + vertexIdx; osg::Vec2& tc( defaultCoord ); if (vIdx < size) tc = (*t2)[ vIdx ]; _records->writeFloat32( tc[0] ); _records->writeFloat32( tc[1] ); } } } } void FltExportVisitor::handleDrawArrays( const osg::DrawArrays* da, const osg::Geometry& geom, const osg::Geode& geode ) { GLint first = da->getFirst(); GLsizei count = da->getCount(); GLenum mode = da->getMode(); int n( 0 ); bool useMesh( false ); switch( mode ) { case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_QUAD_STRIP: useMesh = true; break; case GL_POINTS: n = 1; break; case GL_LINES: n = 2; break; case GL_TRIANGLES: n = 3; break; case GL_QUADS: n = 4; break; case GL_LINE_STRIP: case GL_LINE_LOOP: case GL_POLYGON: default: n = count; break; } if (useMesh) { std::vector< unsigned int > indices; int jdx; for (jdx=0; jdxgetFirst(); GLenum mode = dal->getMode(); int n( 0 ); bool useMesh( false ); switch( mode ) { case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_QUAD_STRIP: useMesh = true; break; case GL_POINTS: n = 1; break; case GL_LINES: n = 2; break; case GL_TRIANGLES: n = 3; break; case GL_QUADS: n = 4; break; case GL_LINE_STRIP: case GL_LINE_LOOP: case GL_POLYGON: default: break; } // Push and pop subfaces if polygon offset is on. SubfaceHelper subface( *this, getCurrentStateSet() ); if (useMesh) { int idx( 0 ); for( osg::DrawArrayLengths::const_iterator itr=dal->begin(); itr!=dal->end(); itr++ ) { std::vector< unsigned int > indices; int jdx; for (jdx=0; jdx<(*itr); idx++, jdx++) indices.push_back( idx ); writeMeshPrimitive( indices, mode ); } } else { // Hm. You wouldn't usually use DrawArrayLengths for non-strip/fan prims... for( osg::DrawArrayLengths::const_iterator itr=dal->begin(); itr!=dal->end(); itr++ ) { while (first+n <= *itr) { writeFace( geode, geom, mode ); writeMatrix( geode.getUserData() ); writeComment( geode ); writeMultitexture( geom ); writePush(); // Write vertex list records. int numVerts; if (n == 0) { numVerts = writeVertexList( first, *itr ); first += *itr; } else { numVerts = writeVertexList( first, n ); first += n; } writeUVList( numVerts, geom ); writePop(); } first += *itr; } } } void FltExportVisitor::handleDrawElements( const osg::DrawElements* de, const osg::Geometry& geom, const osg::Geode& geode ) { GLenum mode = de->getMode(); int n( 0 ); bool useMesh( false ); switch( mode ) { case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_QUAD_STRIP: n = de->getNumIndices(); useMesh = true; break; case GL_POINTS: n = 1; break; case GL_LINES: n = 2; break; case GL_TRIANGLES: n = 3; break; case GL_QUADS: n = 4; break; case GL_LINE_STRIP: case GL_LINE_LOOP: case GL_POLYGON: default: n = de->getNumIndices(); break; } // Push and pop subfaces if polygon offset is on. SubfaceHelper subface( *this, getCurrentStateSet() ); if (useMesh) { std::vector< unsigned int > indices; int idx; for (idx=0; idxindex( idx ) ); writeMeshPrimitive( indices, mode ); } else { unsigned int first( 0 ); while (first+n <= de->getNumIndices()) { // Need: // * Geode for record name (but also need to handle // multi Geometry objects and multi PrimitiveSet objects; // all Face records can't have the same name). // * Mode writeFace( geode, geom, mode ); writeMatrix( geode.getUserData() ); writeComment( geode ); writeMultitexture( geom ); writePush(); // Write vertex list records. std::vector indices; int idx; for(idx=0; idxindex( first+idx ) ); int numVerts = writeVertexList( indices, n ); first += n; writeUVList( numVerts, geom, indices ); writePop(); } } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Vertex.cpp0000644000175000017500000000334313151044751026026 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include "Vertex.h" using namespace flt; Vertex::Vertex(): _coord(0,0,0), _color(1,1,1,1), _normal(0,0,1), _validColor(false), _validNormal(false) { for (int layer=0; layer=0 && layer #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" namespace flt { /** PushLevel */ class PushLevel : public Record { public: PushLevel() {} META_Record(PushLevel) virtual void readRecord(RecordInputStream& /*in*/, Document& document) { document.pushLevel(); } protected: virtual ~PushLevel() {} }; REGISTER_FLTRECORD(PushLevel, PUSH_LEVEL_OP) /** PophLevel */ class PopLevel : public Record { public: PopLevel() {} META_Record(PopLevel) virtual void read(RecordInputStream& /*in*/, Document& document) { PrimaryRecord* parentPrimary = document.getTopOfLevelStack(); PrimaryRecord* currentPrimary = document.getCurrentPrimaryRecord(); // Call dispose() for primary without push, pop level pair. if (currentPrimary && currentPrimary!=parentPrimary) { currentPrimary->dispose(document); } // Call dispose() for primary with push, pop level pair. if (parentPrimary) { parentPrimary->dispose(document); } document.popLevel(); } protected: virtual ~PopLevel() {} }; REGISTER_FLTRECORD(PopLevel, POP_LEVEL_OP) /** PushSubface */ class PushSubface : public Record { public: PushSubface() {} META_Record(PushSubface) virtual void read(RecordInputStream& /*in*/, Document& document) { document.pushSubface(); } protected: virtual ~PushSubface() {} }; REGISTER_FLTRECORD(PushSubface, PUSH_SUBFACE_OP) /** PopSubface */ class PopSubface : public Record { public: PopSubface() {} META_Record(PopSubface) virtual void read(RecordInputStream& /*in*/, Document& document) { document.popSubface(); } protected: virtual ~PopSubface() {} }; REGISTER_FLTRECORD(PopSubface, POP_SUBFACE_OP) /** PushExtension */ class PushExtension : public Record { public: PushExtension() {} META_Record(PushExtension) virtual void read(RecordInputStream& in, Document& document) { readRecord(in,document); document.pushExtension(); } protected: virtual ~PushExtension() {} }; REGISTER_FLTRECORD(PushExtension, PUSH_EXTENSION_OP) /** PopExtension */ class PopExtension : public Record { public: PopExtension() {} META_Record(PopExtension) virtual void read(RecordInputStream& in, Document& document) { readRecord(in,document); document.popExtension(); } protected: virtual ~PopExtension() {} }; REGISTER_FLTRECORD(PopExtension, POP_EXTENSION_OP) /** PushAttribute - Reserved subtree */ class PushAttribute : public Record { public: PushAttribute() {} META_Record(PushAttribute) virtual void read(RecordInputStream& in, Document& document) { readRecord(in,document); } protected: virtual ~PushAttribute() {} }; REGISTER_FLTRECORD(PushAttribute, PUSH_ATTRIBUTE_OP) /** PopAttribute */ class PopAttribute : public Record { public: PopAttribute() {} META_Record(PopAttribute) virtual void read(RecordInputStream& in, Document& document) { readRecord(in,document); } protected: virtual ~PopAttribute() {} }; REGISTER_FLTRECORD(PopAttribute, POP_ATTRIBUTE_OP) } // end namespace OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/Types.h0000644000175000017500000000261613151044751025324 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_TYPES_H #define FLT_TYPES_H 1 namespace flt { #if defined(_MSC_VER) typedef __int8 int8; typedef unsigned __int8 uint8; typedef __int16 int16; typedef unsigned __int16 uint16; typedef __int32 int32; typedef unsigned __int32 uint32; typedef float float32; typedef double float64; #else typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed int int32; typedef unsigned int uint32; typedef float float32; typedef double float64; #endif } // end namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/OpenFlight/ReservedRecords.cpp0000644000175000017500000000216713151044751027655 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ // // OpenFlight loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include "Registry.h" using namespace flt; // Prevent "unknown record" message for the following reserved records: REGISTER_FLTRECORD(DummyRecord, 103) REGISTER_FLTRECORD(DummyRecord, 104) REGISTER_FLTRECORD(DummyRecord, 117) REGISTER_FLTRECORD(DummyRecord, 118) REGISTER_FLTRECORD(DummyRecord, 120) REGISTER_FLTRECORD(DummyRecord, 121) REGISTER_FLTRECORD(DummyRecord, 124) REGISTER_FLTRECORD(DummyRecord, 125) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gstreamer/0000755000175000017500000000000013151044751023774 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gstreamer/ReaderWriterGStreamer.cpp0000644000175000017500000000512313151044751030712 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include "GStreamerImageStream.hpp" #include #include #include class ReaderWriterGStreamer : public osgDB::ReaderWriter { public: ReaderWriterGStreamer() { supportsExtension("avi", ""); supportsExtension("flv", "Flash video"); supportsExtension("mov", "Quicktime"); supportsExtension("ogg", "Theora movie format"); supportsExtension("mpg", "Mpeg movie format"); supportsExtension("mpv", "Mpeg movie format"); supportsExtension("wmv", "Windows Media Video format"); supportsExtension("mkv", "Matroska"); supportsExtension("mjpeg", "Motion JPEG"); supportsExtension("mp4", "MPEG-4"); supportsExtension("m4v", "MPEG-4"); supportsExtension("sav", "Unknown"); supportsExtension("3gp", "3G multi-media format"); supportsExtension("sdp", "Session Description Protocol"); supportsExtension("m2ts", "MPEG-2 Transport Stream"); gst_init(NULL, NULL); } virtual ~ReaderWriterGStreamer() { } virtual const char * className() const { return "ReaderWriterGStreamer"; } virtual ReadResult readImage(const std::string & filename, const osgDB::ReaderWriter::Options* options) const { const std::string ext = osgDB::getLowerCaseFileExtension(filename); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; const std::string path = osgDB::containsServerAddress(filename) ? filename : osgDB::findDataFile(filename, options); if (path.empty()) return ReadResult::FILE_NOT_FOUND; osg::ref_ptr imageStream = new osgGStreamer::GStreamerImageStream(); if (!imageStream->open(filename)) return ReadResult::FILE_NOT_HANDLED; return imageStream.release(); } }; REGISTER_OSGPLUGIN(gstreamer, ReaderWriterGStreamer) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gstreamer/GStreamerImageStream.hpp0000644000175000017500000000252613151044751030522 0ustar albertoalberto#ifndef HEADER_GUARD_OSGGSTREAMER_GSTREAMER_IMAGE_STREAM_H #define HEADER_GUARD_OSGGSTREAMER_GSTREAMER_IMAGE_STREAM_H #include #include #include #include namespace osgGStreamer { class GStreamerImageStream : public osg::ImageStream, public OpenThreads::Thread { public: GStreamerImageStream(); GStreamerImageStream(const GStreamerImageStream & image, const osg::CopyOp & copyop = osg::CopyOp::SHALLOW_COPY); META_Object(osgGStreamer, GStreamerImageStream); bool open(const std::string &filename); virtual void play(); virtual void pause(); virtual void rewind(); virtual void seek(double time); private: virtual ~GStreamerImageStream(); virtual void run(); static gboolean on_message(GstBus *bus, GstMessage *message, GStreamerImageStream *user_data); static GstFlowReturn on_new_sample(GstAppSink *appsink, GStreamerImageStream *user_data); static GstFlowReturn on_new_preroll(GstAppSink *appsink, GStreamerImageStream *user_data); GMainLoop* _loop; GstElement* _pipeline; unsigned char* _internal_buffer; int _width; int _height; }; } #endif // HEADER_GUARD_OSGGSTREAMER_GSTREAMER_IMAGE_STREAM_H OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gstreamer/CMakeLists.txt0000644000175000017500000000113513151044751026534 0ustar albertoalbertoINCLUDE_DIRECTORIES( ${GSTREAMER_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ) SET(TARGET_EXTERNAL_LIBRARIES ${GSTREAMER_LIBRARIES} ${GSTREAMER_APP_LIBRARIES} ${GSTREAMER_PBUTILS_LIBRARIES} ${GLIB_LIBRARIES} ${GLIB_GOBJECT_LIBRARIES} ) SET(TARGET_SRC GStreamerImageStream.cpp ReaderWriterGStreamer.cpp ) SET(TARGET_H GStreamerImageStream.hpp ) IF(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") REMOVE_CXX_FLAG(-pedantic) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros") ENDIF() #### end var setup ### SETUP_PLUGIN(gstreamer) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gstreamer/GStreamerImageStream.cpp0000644000175000017500000001511413151044751030512 0ustar albertoalberto#include "GStreamerImageStream.hpp" #if 0 #define OSGGST_INFO OSG_NOTICE #else #define OSGGST_INFO OSG_INFO #endif namespace osgGStreamer { GStreamerImageStream::GStreamerImageStream(): _loop(0), _pipeline(0), _internal_buffer(0), _width(0), _height(0) { setOrigin(osg::Image::TOP_LEFT); _loop = g_main_loop_new(NULL, FALSE); } GStreamerImageStream::GStreamerImageStream(const GStreamerImageStream & image, const osg::CopyOp & copyop) : osg::ImageStream(image, copyop), _loop(0), _pipeline(0), _internal_buffer(0), _width(0), _height(0) { setOrigin(osg::Image::TOP_LEFT); _loop = g_main_loop_new(NULL, FALSE); if (!getFileName().empty()) { open(getFileName()); } } GStreamerImageStream::~GStreamerImageStream() { gst_element_set_state(_pipeline, GST_STATE_NULL); gst_element_get_state(_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); //wait until the state changed g_main_loop_quit(_loop); g_main_loop_unref(_loop); free(_internal_buffer); } bool GStreamerImageStream::open(const std::string& filename) { setFileName(filename); GError *error = NULL; // get stream info bool has_audio_stream = false; gchar *uri = g_filename_to_uri(filename.c_str(), NULL, NULL); if( uri!=0 && gst_uri_is_valid(uri) ) { GstDiscoverer *item = gst_discoverer_new(1*GST_SECOND, &error); GstDiscovererInfo *info = gst_discoverer_discover_uri(item, uri, &error); GList *audio_list = gst_discoverer_info_get_audio_streams(info); if( g_list_length(audio_list) > 0 ) has_audio_stream = true; gst_discoverer_info_unref(info); g_free(uri); } // build pipeline const gchar *audio_pipe = ""; if( has_audio_stream ) { audio_pipe = "deco. ! queue ! audioconvert ! autoaudiosink"; } gchar *string = g_strdup_printf("filesrc location=%s ! \ decodebin name=deco \ deco. ! queue ! videoconvert ! video/x-raw,format=RGB ! appsink name=sink emit-signals=true \ %s", filename.c_str(), audio_pipe); _pipeline = gst_parse_launch(string, &error); g_free(string); if (error) { g_printerr("Error: %s\n", error->message); g_error_free(error); } if( _pipeline == NULL ) { return false; } // bus GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(_pipeline)); gst_bus_add_watch(bus, (GstBusFunc)on_message, this); gst_object_unref(bus); // sink GstElement *sink = gst_bin_get_by_name(GST_BIN(_pipeline), "sink"); g_signal_connect(sink, "new-sample", G_CALLBACK(on_new_sample), this); g_signal_connect(sink, "new-preroll", G_CALLBACK(on_new_preroll), this); gst_object_unref(sink); gst_element_set_state(_pipeline, GST_STATE_PAUSED); gst_element_get_state(_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); // wait until the state changed if (_width==0 || _height==0) { // no valid image has been setup by a on_new_preroll() call. return false; } // setLoopingMode(osg::ImageStream::NO_LOOPING); // start the thread to run gstreamer main loop start(); return true; } //** Controls ** void GStreamerImageStream::play() { OSGGST_INFO<<"GStreamerImageStream::play()"<_internal_buffer, info.size); // data has been modified so dirty the image so the texture will updated user_data->dirty(); // clean resources gst_buffer_unmap(buffer, &info); gst_sample_unref(sample); return GST_FLOW_OK; } GstFlowReturn GStreamerImageStream::on_new_preroll(GstAppSink *appsink, GStreamerImageStream *user_data) { // get the sample from appsink GstSample *sample = gst_app_sink_pull_preroll(appsink); // get sample info GstCaps *caps = gst_sample_get_caps(sample); GstStructure *structure = gst_caps_get_structure(caps, 0); int width; int height; gst_structure_get_int(structure, "width", &width); gst_structure_get_int(structure, "height", &height); if (width<=0 || height<=0) { OSG_NOTICE<<"Error: video size invalid width="<getFileName()<<"' finished."<getLoopingMode()==osg::ImageStream::LOOPING) { user_data->rewind(); } } return TRUE; } void GStreamerImageStream::run() { g_main_loop_run(_loop); } } // namespace osgGStreamer OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gif/0000755000175000017500000000000013151044751022550 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gif/CMakeLists.txt0000644000175000017500000000046113151044751025311 0ustar albertoalbertoINCLUDE_DIRECTORIES( ${GIFLIB_INCLUDE_DIR} ) SET(TARGET_SRC ReaderWriterGIF.cpp ) SET(TARGET_LIBRARIES_VARS GIFLIB_LIBRARY ) #### end var setup ### SETUP_PLUGIN(gif) IF(MSVC) SET_TARGET_PROPERTIES("${TARGET_DEFAULT_PREFIX}${TARGET_NAME}" PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:MSVCRT") ENDIF() OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gif/ReaderWriterGIF.cpp0000644000175000017500000004706113151044751026211 0ustar albertoalberto#include #include #include #include #include #include #include #include #include /**************************************************************************** * * Follows is code extracted from the simage library. Original Authors: * * Systems in Motion, * * * Peder Blekken * Morten Eriksen * Marius Bugge Monsen * * The original COPYING notice * * All files in this library are public domain, except simage_rgb.cpp which is * Copyright (c) Mark J Kilgard . I will contact Mark * very soon to hear if this source also can become public domain. * * Please send patches for bugs and new features to: . * * Peder Blekken * * * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000. * Note, reference above to license of simage_rgb is not relevant to the OSG * as the OSG does not use it. Also for patches, bugs and new features * please send them direct to the OSG dev team rather than address above. * **********************************************************************/ /*! GIF loader, using libungif Based, in part, on source code found in libungif, gif2rgb.c */ #include #include #include extern "C" { #include } #define ERR_NO_ERROR 0 #define ERR_OPEN 1 #define ERR_READ 2 #define ERR_MEM 3 #define MY_GIF_DEBUG 1 // GifImageStream class class GifImageStream : public osg::ImageStream, public OpenThreads::Thread { public: GifImageStream() : osg::ImageStream(), _multiplier(1.0), _currentLength(0), _length(0), _frameNum(0), _dataNum(0), _done(false) { _status=PAUSED; } virtual Object* clone() const { return new GifImageStream; } virtual bool isSameKindAs( const Object* obj ) const { return dynamic_cast(obj) != NULL; } virtual const char* className() const { return "GifImageStream"; } virtual void play() { if (!isRunning()) start(); _status=PLAYING; } virtual void pause() { _status=PAUSED; } virtual void rewind() { setReferenceTime( 0.0 ); } virtual void quit( bool waitForThreadToExit=true ) { _done = true; if (isRunning() && waitForThreadToExit) { cancel(); join(); } } StreamStatus getStatus() { return _status; } virtual double getLength() const { return _length*0.01*_multiplier; } // Go to a specific position of stream virtual void setReferenceTime( double time ) { OpenThreads::ScopedLock lock(_mutex); int i=1; int framePos = static_cast(time*100.0/_multiplier); if ( framePos>=(int)_length ) framePos = _length; std::vector::iterator it; for ( it=_dataList.begin(); it!=_dataList.end(); it++,i++ ) { framePos -= (*it)->delay; if ( framePos<0 ) break; } _dataNum = i-1; _frameNum = (*it)->delay+framePos; setNewImage(); } virtual double getReferenceTime() const { return _currentLength*0.01*_multiplier; } // Speed up, slow down or back to normal (1.0) virtual void setTimeMultiplier( double m ) { OpenThreads::ScopedLock lock(_mutex); if ( m>0 ) _multiplier = m; } virtual double getTimeMultiplier() const { return _multiplier; } // Not used in GIF animation virtual void setVolume(float) {} virtual float getVolume() const { return 0.0f; } virtual void run() { _dataIter = _dataList.begin(); while ( !_done ) { if ( _status==PLAYING && (*_dataIter) ) { if ( _frameNum>=(*_dataIter)->delay ) { _frameNum = 0; if ( _dataNum>=_dataList.size()-1 ) { if ( getLoopingMode()==LOOPING ) { _dataNum = 0; _currentLength = 0; } } else _dataNum++; setNewImage(); } else { _frameNum++; _currentLength++; } OpenThreads::Thread::microSleep(static_cast(10000.0f*_multiplier)); } else OpenThreads::Thread::microSleep(150000L); } } void addToImageStream( int ss, int tt, int rr, int numComponents, int delayTime, unsigned char* imgData ) { if ( isRunning() ) { OSG_WARN<<"GifImageStream::addToImageStream: thread is running!"<delay = delayTime; newData->data = imgData; _dataList.push_back( newData ); _length += delayTime; } protected: typedef struct { unsigned int delay; unsigned char* data; } FrameData; void setNewImage() { _dataIter = _dataList.begin()+_dataNum; if ( *_dataIter ) { unsigned char* image = (*_dataIter)->data; setImage(_s,_t,_r,_internalTextureFormat,_pixelFormat,_dataType, image,osg::Image::NO_DELETE,1); dirty(); } } virtual ~GifImageStream() { if( isRunning() ) quit( true ); std::vector::iterator it; for ( it=_dataList.begin(); it!=_dataList.end(); it++ ) { delete (*it)->data; delete (*it); } } double _multiplier; unsigned int _currentLength; unsigned int _length; unsigned int _frameNum; unsigned int _dataNum; std::vector _dataList; std::vector::iterator _dataIter; bool _done; OpenThreads::Mutex _mutex; }; static int giferror = ERR_NO_ERROR; int simage_gif_error(char * buffer, int buflen) { switch (giferror) { case ERR_OPEN: strncpy(buffer, "GIF loader: Error opening file", buflen); break; case ERR_READ: strncpy(buffer, "GIF loader: Error reading file", buflen); break; case ERR_MEM: strncpy(buffer, "GIF loader: Out of memory error", buflen); break; } return giferror; } int simage_gif_identify(const char *, const unsigned char *header, int headerlen) { static unsigned char gifcmp[] = {'G', 'I', 'F'}; if (headerlen < 3) return 0; if (memcmp((const void*)header, (const void*)gifcmp, 3) == 0) return 1; return 0; } static void decode_row(GifFileType * giffile, unsigned char * buffer, unsigned char * rowdata, int x, int y, int len, int transparent) { GifColorType * cmentry; ColorMapObject * colormap; int colormapsize; unsigned char col; unsigned char * ptr; y = giffile->SHeight - (y+1); ptr = buffer + (giffile->SWidth * y + x) * 4; colormap = (giffile->Image.ColorMap ? giffile->Image.ColorMap : giffile->SColorMap); colormapsize = colormap ? colormap->ColorCount : 255; while (len--) { col = *rowdata++; /* just in case */ if (col >= colormapsize) col = 0; if ( col == transparent ) { // keep pixels of last image if transparent mode is on // this is necessary for GIF animating ptr += 3; } else { cmentry = colormap ? &colormap->Colors[col] : NULL; if (cmentry) { *ptr++ = cmentry->Red; *ptr++ = cmentry->Green; *ptr++ = cmentry->Blue; } else { *ptr++ = col; *ptr++ = col; *ptr++ = col; } } *ptr++ = (col == transparent ? 0x00 : 0xff); } } int gif_read_stream(GifFileType *gfile, GifByteType *gdata, int glength) { std::istream *stream = (std::istream*)gfile->UserData; //Get pointer to istream stream->read((char*)gdata,glength); //Read requested amount of data return stream->gcount(); } unsigned char * simage_gif_load(std::istream& fin, int *width_ret, int *height_ret, int *numComponents_ret, GifImageStream** obj) { int i, j, n, row, col, width, height, extcode; unsigned char * rowdata; unsigned char * buffer, * ptr; unsigned char bg; int transparent, delaytime; GifRecordType recordtype; GifByteType * extension; GifFileType * giffile; GifColorType * bgcol; /* The way an interlaced image should be read - offsets and jumps */ int interlacedoffset[] = { 0, 4, 2, 1 }; int interlacedjumps[] = { 8, 8, 4, 2 }; #if (GIFLIB_MAJOR >= 5) int Error; giffile = DGifOpen(&fin,gif_read_stream, &Error); #else giffile = DGifOpen(&fin,gif_read_stream); #endif if (!giffile) { giferror = ERR_OPEN; return NULL; } transparent = -1; /* no transparent color by default */ delaytime = 8; /* delay time of a frame */ n = giffile->SHeight * giffile->SWidth; buffer = new unsigned char [n * 4]; if (!buffer) { giferror = ERR_MEM; return NULL; } rowdata = new unsigned char [giffile->SWidth]; if (!rowdata) { giferror = ERR_MEM; delete [] buffer; return NULL; } bg = giffile->SBackGroundColor; if (giffile->SColorMap && bg < giffile->SColorMap->ColorCount) { bgcol = &giffile->SColorMap->Colors[bg]; } else bgcol = NULL; ptr = buffer; for (i = 0; i < n; i++) { if (bgcol) { *ptr++ = bgcol->Red; *ptr++ = bgcol->Green; *ptr++ = bgcol->Blue; *ptr++ = 0xff; } else { *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0xff; } } /* Scan the content of the GIF file and load the image(s) in: */ int gif_num=0; do { if (DGifGetRecordType(giffile, &recordtype) == GIF_ERROR) { giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } switch (recordtype) { case IMAGE_DESC_RECORD_TYPE: /* start recording image stream if more than one image found */ gif_num++; if ( gif_num==2 ) { *obj = new GifImageStream; (*obj)->addToImageStream( giffile->SWidth, giffile->SHeight, 1, 4, delaytime, buffer ); unsigned char* destbuffer = new unsigned char [n * 4]; buffer = (unsigned char*)memcpy( destbuffer, buffer, n*4 ); } if (DGifGetImageDesc(giffile) == GIF_ERROR) { giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } /* subimage position in composite image */ row = giffile->Image.Top; col = giffile->Image.Left; width = giffile->Image.Width; height = giffile->Image.Height; if (giffile->Image.Left + giffile->Image.Width > giffile->SWidth || giffile->Image.Top + giffile->Image.Height > giffile->SHeight) { /* image is not confined to screen dimension */ giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } if (giffile->Image.Interlace) { //fprintf(stderr,"interlace\n"); /* Need to perform 4 passes on the images: */ for (i = 0; i < 4; i++) { for (j = row + interlacedoffset[i]; j < row + height; j += interlacedjumps[i]) { if (DGifGetLine(giffile, rowdata, width) == GIF_ERROR) { giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } else decode_row(giffile, buffer, rowdata, col, j, width, transparent); } } } else { for (i = 0; i < height; i++, row++) { if (DGifGetLine(giffile, rowdata, width) == GIF_ERROR) { giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } else decode_row(giffile, buffer, rowdata, col, row, width, transparent); } } // Record gif image stream if ( *obj && obj ) { (*obj)->addToImageStream( giffile->SWidth, giffile->SHeight, 1, 4, delaytime, buffer ); unsigned char* destbuffer = new unsigned char [n * 4]; buffer = (unsigned char*)memcpy( destbuffer, buffer, n*4 ); } break; case EXTENSION_RECORD_TYPE: /* Skip any extension blocks in file: */ if (DGifGetExtension(giffile, &extcode, &extension) == GIF_ERROR) { giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } /* transparent test from the gimp gif-plugin. Open Source rulez! */ else if (extcode == 0xf9) { if (extension[0] >= 4 && extension[1] & 0x1) transparent = extension[4]; else transparent = -1; delaytime = (extension[3]<<8)+extension[2]; // minimum unit 1/100s, so 8 here means 8/100s } while (extension != NULL) { if (DGifGetExtensionNext(giffile, &extension) == GIF_ERROR) { giferror = ERR_READ; delete [] buffer; delete [] rowdata; return NULL; } } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType. */ break; } } while (recordtype != TERMINATE_RECORD_TYPE); // Delete the last allocated buffer to avoid memory leaks if we using GifImageStream if ( obj && *obj ) { delete [] buffer; buffer = 0; } delete [] rowdata; *width_ret = giffile->SWidth; *height_ret = giffile->SHeight; *numComponents_ret = 4; #if (GIFLIB_MAJOR >= 5&& !(GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)) DGifCloseFile(giffile, &Error); #else DGifCloseFile(giffile); #endif return buffer; } class ReaderWriterGIF : public osgDB::ReaderWriter { public: ReaderWriterGIF() { supportsExtension("gif","GIF Image format"); } virtual const char* className() const { return "GIF Image Reader"; } ReadResult readGIFStream(std::istream& fin) const { unsigned char *imageData = NULL; int width_ret; int height_ret; int numComponents_ret; GifImageStream* gifStream = NULL; imageData = simage_gif_load( fin,&width_ret,&height_ret,&numComponents_ret, &gifStream ); switch (giferror) { case ERR_OPEN: return ReadResult("GIF loader: Error opening file"); case ERR_READ: return ReadResult("GIF loader: Error reading file"); case ERR_MEM: return ReadResult("GIF loader: Out of memory error"); } // Use GifImageStream to display animate GIFs if ( gifStream ) { OSG_DEBUG<<"Using GifImageStream ..."<setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); return pOsgImage; } virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(fin, options); } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(file, options); } virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const { return readGIFStream(fin); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::FILE_NOT_HANDLED; ReadResult rr = readGIFStream(istream); if(rr.validImage()) rr.getImage()->setFileName(file); return rr; } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(gif, ReaderWriterGIF) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/0000755000175000017500000000000013151044751024500 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/OSXAVFoundationVideo.mm0000644000175000017500000004132313151044751030754 0ustar albertoalberto#include "OSXAVFoundationVideo.h" #include #include #include #include #import #import "TargetConditionals.h" #if (TARGET_OS_IPHONE) #import #include #else #import #include #endif #include "OSXAVFoundationCoreVideoTexture.h" namespace { static NSString* toNSString(const std::string& str) { return [NSString stringWithUTF8String: str.c_str()]; } static std::string toString(NSString* str) { return str ? std::string([str UTF8String]) : ""; } class NSAutoreleasePoolHelper { public: NSAutoreleasePoolHelper() { _pool = [[NSAutoreleasePool alloc] init]; } ~NSAutoreleasePoolHelper() { [_pool release]; } private: NSAutoreleasePool* _pool; }; } @interface AVPlayer (MOAdditions) - (NSURL *)currentURL; - (void)setVolume:(CGFloat)volume; @end; @implementation AVPlayer (MOAdditions) - (NSURL *)currentURL { AVAsset *asset = self.currentItem.asset; if ([asset isMemberOfClass:[AVURLAsset class]]) return ((AVURLAsset *)asset).URL; return nil; } - (void)setVolume:(CGFloat)volume { NSArray *audioTracks = [self.currentItem.asset tracksWithMediaType:AVMediaTypeAudio]; NSMutableArray *allAudioParams = [NSMutableArray array]; for (AVAssetTrack *track in audioTracks) { AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; [audioInputParams setVolume:volume atTime:kCMTimeZero]; [audioInputParams setTrackID:[track trackID]]; [allAudioParams addObject:audioInputParams]; } AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; [audioMix setInputParameters:allAudioParams]; [self.currentItem setAudioMix:audioMix]; } @end @interface OSXAVFoundationVideoDelegate : NSObject { OSXAVFoundationVideo* video; } @property (readwrite,assign) OSXAVFoundationVideo* video; - (void) playerItemDidReachEnd:(NSNotification*)the_notification; @end; @implementation OSXAVFoundationVideoDelegate @synthesize video; - (void) playerItemDidReachEnd:(NSNotification*)the_notification { if (video->getLoopingMode() == osg::ImageStream::LOOPING) { video->seek(0); } else { video->pause(); } } @end class OSXAVFoundationVideo::Data { public: AVPlayer* avplayer; AVPlayerItemVideoOutput* output; OSXAVFoundationVideoDelegate* delegate; std::vector lastFrames; int readFrameNdx, writeFrameNdx; #if (TARGET_OS_IPHONE) CVOpenGLESTextureCacheRef coreVideoTextureCache; #else CVOpenGLTextureCacheRef coreVideoTextureCache; #endif Data() : avplayer(NULL) , output(NULL) , delegate(NULL) , lastFrames(3) , readFrameNdx(0) , writeFrameNdx(0) , coreVideoTextureCache(0) { } void clear() { if (delegate) { [[NSNotificationCenter defaultCenter] removeObserver: delegate name:AVPlayerItemDidPlayToEndTimeNotification object:avplayer.currentItem ]; [delegate release]; } if (avplayer) { [avplayer cancelPendingPrerolls]; [avplayer.currentItem.asset cancelLoading]; [avplayer.currentItem removeOutput:output]; } [output release]; [avplayer release]; avplayer = NULL; output = NULL; delegate = NULL; } ~Data() { clear(); for(unsigned int i=0; i< lastFrames.size(); ++i) { if (lastFrames[i]) { CVBufferRelease(lastFrames[i]); } } if (coreVideoTextureCache) { #if (TARGET_OS_IPHONE) CFRelease(coreVideoTextureCache); // huh, there's no CVOpenGLESTextureCacheRelease? #else CVOpenGLTextureCacheRelease(coreVideoTextureCache); #endif coreVideoTextureCache = NULL; } } void addFrame(CVBufferRef frame) { unsigned int new_ndx = writeFrameNdx + 1; if (new_ndx >= lastFrames.size()) new_ndx = 0; if (new_ndx == readFrameNdx) { new_ndx = readFrameNdx+1; if (new_ndx >= lastFrames.size()) new_ndx = 0; } if (lastFrames[new_ndx]) { CVBufferRelease(lastFrames[new_ndx]); } lastFrames[new_ndx] = frame; writeFrameNdx = new_ndx; //std::cout << "new frame: " << writeFrameNdx << std::endl; } bool hasNewFrame() const { return readFrameNdx != writeFrameNdx; } CVBufferRef getLastFrame() { readFrameNdx = writeFrameNdx; // std::cout << "get frame: " << readFrameNdx << std::endl; return lastFrames[readFrameNdx]; } }; OSXAVFoundationVideo::OSXAVFoundationVideo() : osgVideo::VideoImageStream() , _volume(1.0) , _fileOpened(false) , _useCoreVideo(false) , _dimensionsChangedCallbackNeeded(false) { _data = new Data(); _status = INVALID; setOrigin(TOP_LEFT); // std::cout << " OSXAVFoundationVideo " << this << std::endl; } OSXAVFoundationVideo::~OSXAVFoundationVideo() { // std::cout << "~OSXAVFoundationVideo " << this << " " << _data->avplayer << std::endl; quit(); clear(); if (_data) delete _data; } void OSXAVFoundationVideo::play() { if (_data->avplayer) { [_data->avplayer play]; _status = PLAYING; setNeedsDispatching(RequestContinuousUpdate); } } void OSXAVFoundationVideo::setTimeMultiplier(double rate) { if (_data->avplayer) { _data->avplayer.rate = rate; _status = (rate != 0.0) ? PLAYING : PAUSED; setNeedsDispatching(_status == PLAYING ? RequestContinuousUpdate: StopUpdate); } } double OSXAVFoundationVideo::getTimeMultiplier() const { return _data->avplayer ? _data->avplayer.rate : 0.0f; } void OSXAVFoundationVideo::pause() { setNeedsDispatching(StopUpdate); NSAutoreleasePoolHelper helper; if (_data->avplayer) { [_data->avplayer pause]; _status = PAUSED; } } void OSXAVFoundationVideo::clear() { if (_data) _data->clear(); } void OSXAVFoundationVideo::quit(bool t) { pause(); } void OSXAVFoundationVideo::seek(double pos) { static CMTime tolerance = CMTimeMakeWithSeconds(0.01, 600); if(_data->avplayer) [_data->avplayer seekToTime: CMTimeMakeWithSeconds(pos, 600) toleranceBefore: tolerance toleranceAfter: tolerance]; requestNewFrame(); } double OSXAVFoundationVideo::getCurrentTime () const { return _data->avplayer ? CMTimeGetSeconds([_data->avplayer currentTime]) : 0; } void OSXAVFoundationVideo::open(const std::string& filename) { NSAutoreleasePoolHelper helper; clear(); _data->delegate = [[OSXAVFoundationVideoDelegate alloc] init]; _data->delegate.video = this; NSURL* url(NULL); if (osgDB::containsServerAddress(filename)) { url = [NSURL URLWithString: toNSString(filename)]; } else { url = [NSURL fileURLWithPath: toNSString(filename)]; } _data->output = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes: [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, [NSNumber numberWithInteger:1], kCVPixelBufferBytesPerRowAlignmentKey, [NSNumber numberWithBool:YES], kCVPixelBufferOpenGLCompatibilityKey, nil]]; if (_data->output) { _data->output.suppressesPlayerRendering = YES; } _data->avplayer = [AVPlayer playerWithURL: url]; // AVPlayerFactory::instance()->getOrCreate(url); [_data->avplayer retain]; _data->avplayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; [_data->avplayer.currentItem addOutput:_data->output]; [[NSNotificationCenter defaultCenter] addObserver: _data->delegate selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:_data->avplayer.currentItem]; _videoDuration = CMTimeGetSeconds([_data->avplayer.currentItem duration]); // get the max size of the video-tracks NSArray* tracks = [_data->avplayer.currentItem.asset tracksWithMediaType: AVMediaTypeVideo]; CGSize size; for(unsigned int i=0; i < [tracks count]; ++i) { AVAssetTrack* track = [tracks objectAtIndex:i]; size = track.naturalSize; _framerate = track.nominalFrameRate; CGAffineTransform txf = [track preferredTransform]; osg::Matrixf mat; mat.makeIdentity(); if(!CGAffineTransformIsIdentity(txf)) { // user should take this into account and transform accordingly... mat(0,0) = txf.a; mat(1,0) = txf.c; mat(3,0) = txf.tx; mat(0,1) = txf.b; mat(1,1) = txf.d; mat(3,1) = txf.ty; } this->setUserValue("preferredTransform", mat); } _s = size.width; _t = size.height; _r = 1; unsigned char* buffer = (unsigned char*)calloc(_s*_t*4, 1); setImage(_s, _t, 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, buffer, USE_MALLOC_FREE); _fileName = filename; requestNewFrame(); _status = PAUSED; _fileOpened = true; } float OSXAVFoundationVideo::getVolume() const { return _volume; } void OSXAVFoundationVideo::setVolume(float v) { NSAutoreleasePoolHelper helper; _volume = v; if (_data->avplayer) [_data->avplayer setVolume: v]; } float OSXAVFoundationVideo::getAudioBalance() { return 0.0f; } void OSXAVFoundationVideo::setAudioBalance(float b) { OSG_WARN << "OSXAVFoundationVideo: setAudioBalance not supported!" << std::endl; } void OSXAVFoundationVideo::decodeFrame() { // std::cout << this << " decodeFrame: " << _waitForFrame << std::endl; if (!_fileOpened) return; NSAutoreleasePoolHelper helper; bool is_valid = (_data && (_data->avplayer.status != AVPlayerStatusFailed)); if (!is_valid) { _waitForFrame = false; pause(); OSG_WARN << "OSXAVFoundationVideo: " << toString([_data->avplayer.error localizedFailureReason]) << std::endl; } bool is_playing = is_valid && (getTimeMultiplier() != 0); CMTime outputItemTime = [_data->output itemTimeForHostTime:CACurrentMediaTime()]; if (_waitForFrame || [_data->output hasNewPixelBufferForItemTime:outputItemTime]) { CVPixelBufferRef newframe = [_data->output copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL]; if (newframe) { if (isCoreVideoUsed()) { CVPixelBufferLockBaseAddress(newframe, kCVPixelBufferLock_ReadOnly); int w = CVPixelBufferGetWidth(newframe); int h = CVPixelBufferGetHeight(newframe); #if (TARGET_OS_IPHONE) CVOpenGLESTextureRef texture = NULL; CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _data->coreVideoTextureCache, newframe, NULL, GL_TEXTURE_2D, GL_RGBA, w, h, GL_BGRA, GL_UNSIGNED_BYTE, 0, &texture); if (err) { OSG_WARN << "OSXAVFoundationVideo :: could not create texture from image, err: " << err << std::endl; } _data->addFrame(texture); #else CVOpenGLTextureRef texture = NULL; CVReturn err = CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _data->coreVideoTextureCache, newframe, 0, &texture); if (err) { OSG_WARN << "OSXAVFoundationVideo :: could not create texture from image, err: " << err << std::endl; } _data->addFrame(texture); #endif _dimensionsChangedCallbackNeeded = (_s != w) || (_t != h); _s = w; _t = h; _r = 1; CVPixelBufferUnlockBaseAddress(newframe, kCVPixelBufferLock_ReadOnly); CVPixelBufferRelease(newframe); } else { _data->addFrame(newframe); } _waitForFrame = false; } } _status = is_valid ? is_playing ? PLAYING : PAUSED : INVALID; } void OSXAVFoundationVideo::update(osg::NodeVisitor *) { if (!getVideoFrameDispatcher()) decodeFrame(); if (isCoreVideoUsed()) { if (_dimensionsChangedCallbackNeeded) handleDimensionsChangedCallbacks(); _dimensionsChangedCallbackNeeded = false; return; } if (_data->hasNewFrame()) { CVPixelBufferRef newframe = _data->getLastFrame(); CVPixelBufferLockBaseAddress(newframe,kCVPixelBufferLock_ReadOnly); size_t width = CVPixelBufferGetWidth(newframe); size_t height = CVPixelBufferGetHeight(newframe); size_t bpr = CVPixelBufferGetBytesPerRow(newframe); // Get the base address of the pixel buffer void *baseAddress = CVPixelBufferGetBaseAddress(newframe); setImage(width, height, 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, (unsigned char*)baseAddress, NO_DELETE, 1, bpr/4); // std::cout << this << " new frame: " << width << "x" << height << " " << baseAddress << std::endl; CVPixelBufferUnlockBaseAddress(newframe, kCVPixelBufferLock_ReadOnly); } } bool OSXAVFoundationVideo::needsDispatching() const { // std::cout << this << " needs dispatching: " << (_waitForFrame || getNeedsDispatching()) << std::endl; return _waitForFrame || getNeedsDispatching(); } void OSXAVFoundationVideo::applyLoopingMode() { // looping is handled by the delegate } void OSXAVFoundationVideo::requestNewFrame() { setNeedsDispatching(RequestSingleUpdate); _waitForFrame = true; } bool OSXAVFoundationVideo::getCurrentCoreVideoTexture(GLenum& target, GLint& name, int& width, int& height) const { #if (TARGET_OS_IPHONE) CVOpenGLESTextureCacheFlush(_data->coreVideoTextureCache, 0); CVOpenGLESTextureRef texture = _data->getLastFrame(); if(texture) { target = GL_TEXTURE_2D; name = CVOpenGLESTextureGetName(texture); width = _s; height = _t; } return (texture != NULL); #else CVOpenGLTextureCacheFlush(_data->coreVideoTextureCache, 0); CVOpenGLTextureRef texture = _data->getLastFrame(); if (texture) { target = CVOpenGLTextureGetTarget(texture); name = CVOpenGLTextureGetName(texture); width = _s; height = _t; } return (texture != NULL); #endif } void OSXAVFoundationVideo::lazyInitCoreVideoTextureCache(osg::State& state) { if (_data->coreVideoTextureCache) return; #if (TARGET_OS_IPHONE) osgViewer::GraphicsWindowIOS* win = dynamic_cast(state.getGraphicsContext()); if (win) { EAGLContext* context = win->getContext(); CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, context, NULL, &_data->coreVideoTextureCache); if (err) { OSG_WARN << "OSXAVFoundationVideo : could not create texture cache :" << err << std::endl; } } #else osgViewer::GraphicsWindowCocoa* win = dynamic_cast(state.getGraphicsContext()); if (win) { NSOpenGLContext* context = win->getContext(); CGLContextObj cglcntx = (CGLContextObj)[context CGLContextObj]; CGLPixelFormatObj cglPixelFormat = (CGLPixelFormatObj)[ win->getPixelFormat() CGLPixelFormatObj]; CVReturn cvRet = CVOpenGLTextureCacheCreate(kCFAllocatorDefault, 0, cglcntx, cglPixelFormat, 0, &_data->coreVideoTextureCache); if (cvRet != kCVReturnSuccess) { OSG_WARN << "OSXAVFoundationVideo : could not create texture cache :" << cvRet << std::endl; } } #endif } osg::Texture* OSXAVFoundationVideo::createSuitableTexture() { #if (TARGET_OS_IPHONE) return new OSXAVFoundationCoreVideoTexture(this); #else return NULL; // new OSXAVFoundationCoreVideoTexture(this); #endif } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/OSXAVFoundationCoreVideoTexture.cpp0000644000175000017500000001047613151044751033324 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #import "TargetConditionals.h" #if (TARGET_OS_IPHONE) #define COREVIDEO_TEXTURE_TARGET GL_TEXTURE_2D #else #define COREVIDEO_TEXTURE_TARGET GL_TEXTURE_RECTANGLE_EXT #endif #include "OSXAVFoundationCoreVideoTexture.h" #include "OSXAVFoundationVideo.h" #include OSXAVFoundationCoreVideoTexture::OSXAVFoundationCoreVideoTexture() : osg::Texture() , _textureTarget(COREVIDEO_TEXTURE_TARGET) , _textureWidth(0) , _textureHeight(0) , _inited(false) { } OSXAVFoundationCoreVideoTexture::OSXAVFoundationCoreVideoTexture(osg::Image* image) : osg::Texture() , _textureTarget(COREVIDEO_TEXTURE_TARGET) , _textureWidth(0) , _textureHeight(0) , _inited(false) { setImage(image); } OSXAVFoundationCoreVideoTexture::OSXAVFoundationCoreVideoTexture(const OSXAVFoundationCoreVideoTexture& text,const osg::CopyOp& copyop) : osg::Texture(text, copyop) , _textureTarget(text._textureTarget) , _textureWidth(text._textureWidth) , _textureHeight(text._textureHeight) , _inited(text._inited) , _image(text._image) { } OSXAVFoundationCoreVideoTexture::~OSXAVFoundationCoreVideoTexture() { } int OSXAVFoundationCoreVideoTexture::compare(const osg::StateAttribute& sa) const { COMPARE_StateAttribute_Types(OSXAVFoundationCoreVideoTexture,sa) if (_image!=rhs._image) // smart pointer comparison. { if (_image.valid()) { if (rhs._image.valid()) { int result = _image->compare(*rhs._image); if (result!=0) return result; } else { return 1; // valid lhs._image is greater than null. } } else if (rhs._image.valid()) { return -1; // valid rhs._image is greater than null. } } if (!_image && !rhs._image) { // no image attached to either Texture2D // but could these textures already be downloaded? // check the _textureObjectBuffer to see if they have been // downloaded int result = compareTextureObjects(rhs); if (result!=0) return result; } int result = compareTexture(rhs); if (result!=0) return result; // compare each parameter in turn against the rhs. #if 1 if (_textureWidth != 0 && rhs._textureWidth != 0) { COMPARE_StateAttribute_Parameter(_textureWidth) } if (_textureHeight != 0 && rhs._textureHeight != 0) { COMPARE_StateAttribute_Parameter(_textureHeight) } #endif return 0; // passed all the above comparison macro's, must be equal. } void OSXAVFoundationCoreVideoTexture::setImage(osg::Image* image) { if (_image == image) return; if (_image.valid() && _image->requiresUpdateCall()) { setUpdateCallback(0); setDataVariance(osg::Object::STATIC); } _image = image; _modifiedCount.setAllElementsTo(0); if (_image.valid() && _image->requiresUpdateCall()) { setUpdateCallback(new osg::Image::UpdateCallback()); setDataVariance(osg::Object::DYNAMIC); } OSXAVFoundationVideo* m = dynamic_cast(_image.get()); if (m) m->setUseCoreVideo(true); } void OSXAVFoundationCoreVideoTexture::apply(osg::State& state) const { if (!_image.valid()) return; OSXAVFoundationVideo* m = dynamic_cast(_image.get()); if ((m) && (m->isCoreVideoUsed())) { m->lazyInitCoreVideoTextureCache(state); GLint texture_name; if (m->getCurrentCoreVideoTexture(_textureTarget, texture_name, _textureWidth, _textureHeight)) { glBindTexture(_textureTarget, texture_name); } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/ReaderWriterAVFoundation.cpp0000644000175000017500000001156513151044751032071 0ustar albertoalberto#include #include #include #include #include #include #include "OSXAVFoundationVideo.h" #include "OSXAVFoundationCoreVideoTexture.h" class ReaderWriterAVFoundation : public osgDB::ReaderWriter { public: ReaderWriterAVFoundation() { supportsExtension("mov","Quicktime movie format"); supportsExtension("mpg","Mpeg movie format"); supportsExtension("mp4","Mpeg movie format"); supportsExtension("m4v","Mpeg movie format"); supportsExtension("mpeg","Mpeg movie format"); supportsExtension("avfoundation","AVFoundation movie format"); supportsProtocol("http", "streaming media per http"); supportsProtocol("rtsp", "streaming media per rtsp"); } virtual bool acceptsExtension(const std::string& extension) const { return osgDB::equalCaseInsensitive(extension,"mov") || osgDB::equalCaseInsensitive(extension,"mpg") || osgDB::equalCaseInsensitive(extension,"mp4") || osgDB::equalCaseInsensitive(extension,"mpv") || osgDB::equalCaseInsensitive(extension,"mpeg")|| osgDB::equalCaseInsensitive(extension,"avfoundation"); } virtual ~ReaderWriterAVFoundation() { OSG_INFO<<"~ReaderWriterAVFoundation()"< video = new OSXAVFoundationVideo(); bool disable_multi_threaded_frame_dispatching = options ? (options->getPluginStringData("disableMultiThreadedFrameDispatching") == "true") : false; bool disable_core_video = options ? (options->getPluginStringData("disableCoreVideo") == "true") : false; OSG_INFO << "disableMultiThreadedFrameDispatching: " << disable_multi_threaded_frame_dispatching << std::endl; OSG_INFO << "disableCoreVideo : " << disable_core_video << std::endl; if (!options || (!disable_multi_threaded_frame_dispatching && disable_core_video)) { static osg::ref_ptr video_frame_dispatcher(NULL); if (!video_frame_dispatcher) { std::string num_threads_str = options ? options->getPluginStringData("numFrameDispatchThreads") : "0"; video_frame_dispatcher = new osgVideo::VideoFrameDispatcher(atoi(num_threads_str.c_str())); } video_frame_dispatcher->addVideo(video); } video->open(fileName); return video->valid() ? video.release() : NULL; } virtual ReadResult readObject (const std::string &file, const osgDB::ReaderWriter::Options* options) const { ReadResult rr = readImage(file, options); if (!rr.validImage()) return rr; bool use_core_video = true; if (options && !options->getPluginStringData("disableCoreVideo").empty()) use_core_video = false; osg::ref_ptr video = dynamic_cast(rr.getImage()); if (!video || !use_core_video) return rr; osg::ref_ptr texture = video->createSuitableTexture(); if (texture.valid()) return texture.release(); return video.release(); } protected: }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(avfoundation, ReaderWriterAVFoundation) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/OSXAVFoundationVideo.h0000644000175000017500000000576113151044751030600 0ustar albertoalberto// // OSXAVFoundationVideo.h // cefix_presentation_ios // // Created by Stephan Maximilian Huber on 25.07.12. // Copyright (c) 2012 stephanmaximilianhuber.com. All rights reserved. // #pragma once #include #include "../QTKit/VideoFrameDispatcher.h" class OSXAVFoundationVideo : public osgVideo::VideoImageStream { public: OSXAVFoundationVideo(); /// Destructor ~OSXAVFoundationVideo(); virtual Object* clone() const { return new OSXAVFoundationVideo(); } virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj) != NULL; } virtual const char* className() const { return "OSXAVFoundationVideo"; } /// Start or continue stream. virtual void play(); /** @return true, if a movie is playing */ bool isPlaying() const { return (getStatus() == PLAYING); } /// sets the movierate void setTimeMultiplier(double rate); /// gets the movierate double getTimeMultiplier() const; /// Pause stream at current position. virtual void pause(); /// stop playing virtual void quit(bool /*waitForThreadToExit*/ = true); /// Get total length in seconds. virtual double getLength() const { return _videoDuration; } /// jumps to a specific position virtual void seek(double pos); virtual void rewind() { seek(0); } /// returns the current playing position virtual double getCurrentTime () const; void open(const std::string& filename); /** @return the current volume as float */ virtual float getVolume() const; /** sets the volume of this quicktime to v*/ virtual void setVolume(float v); /** @return the current balance-setting (0 = neutral, -1 = left, 1 = right */ virtual float getAudioBalance(); /** sets the current balance-setting (0 = neutral, -1 = left, 1 = right */ virtual void setAudioBalance(float b); virtual double getFrameRate () const { return _framerate; } virtual void decodeFrame(); virtual bool valid() const { return (getStatus() != INVALID); } virtual bool requiresUpdateCall () const { return true; } virtual void update(osg::NodeVisitor *); virtual void applyLoopingMode(); void setUseCoreVideo(bool b) { _useCoreVideo = b; } bool isCoreVideoUsed() const { return _useCoreVideo; } void lazyInitCoreVideoTextureCache(osg::State& state); bool getCurrentCoreVideoTexture(GLenum& target, GLint& name, int& width, int& height) const; virtual osg::Texture* createSuitableTexture(); protected: virtual bool needsDispatching() const; void requestNewFrame(); private: class Data; void clear(); float _videoDuration; double _volume; bool _fileOpened, _waitForFrame; Data* _data; bool _useCoreVideo, _dimensionsChangedCallbackNeeded; double _framerate; }; OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/CMakeLists.txt0000644000175000017500000000072413151044751027243 0ustar albertoalberto SET(TARGET_SRC OSXAVFoundationVideo.mm OSXAVFoundationVideo.h ../QTKit/VideoFrameDispatcher.h ../QTKit/VideoFrameDispatcher.cpp OSXAVFoundationCoreVideoTexture.h OSXAVFoundationCoreVideoTexture.cpp ReaderWriterAVFoundation.cpp ) SET(TARGET_LIBRARIES_VARS AV_FOUNDATION_LIBRARY COCOA_LIBRARY COREVIDEO_LIBRARY COREMEDIA_LIBRARY QUARTZCORE_LIBRARY) SET(TARGET_ADDED_LIBRARIES osgViewer ) #### end var setup ### SETUP_PLUGIN(avfoundation) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/avfoundation/OSXAVFoundationCoreVideoTexture.h0000644000175000017500000000523313151044751032764 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #pragma once #include class OSXAVFoundationCoreVideoTexture : public osg::Texture { public: OSXAVFoundationCoreVideoTexture(); OSXAVFoundationCoreVideoTexture(osg::Image* image); OSXAVFoundationCoreVideoTexture(const OSXAVFoundationCoreVideoTexture& text,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); META_StateAttribute( , OSXAVFoundationCoreVideoTexture, TEXTURE); virtual int compare(const osg::StateAttribute& rhs) const; virtual GLenum getTextureTarget() const { return _textureTarget; } virtual void setImage(unsigned int, osg::Image* image) { setImage(image); } void setImage(osg::Image* image); osg::Image* getImage() { return _image.get(); } const osg::Image* getImage() const { return _image.get(); } virtual osg::Image* getImage(unsigned int) { return _image.get(); } virtual const osg::Image* getImage(unsigned int) const { return _image.get(); } virtual unsigned int getNumImages() const { return 1; } virtual int getTextureWidth() const { return _textureWidth; } virtual int getTextureHeight() const { return _textureHeight; } virtual int getTextureDepth() const { return 1; } virtual void apply(osg::State& state) const; virtual void allocateMipmap(osg::State& state) const {} inline unsigned int& getModifiedCount(unsigned int contextID) const { return _modifiedCount[contextID]; } protected: virtual void computeInternalFormat() const {} virtual ~OSXAVFoundationCoreVideoTexture(); mutable GLenum _textureTarget; mutable int _textureWidth; mutable int _textureHeight; bool _inited; osg::ref_ptr _image; typedef osg::buffered_value ImageModifiedCount; mutable ImageModifiedCount _modifiedCount; }; OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/0000755000175000017500000000000013151044751022567 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPData.cpp0000644000175000017500000001116613151044751024644 0ustar albertoalberto #include "VBSPData.h" #include using namespace bsp; using namespace osg; VBSPData::VBSPData() { } VBSPData::~VBSPData() { } void VBSPData::addEntity(std::string & newEntity) { entity_list.push_back(newEntity); } const int VBSPData::getNumEntities() const { return entity_list.size(); } const std::string & VBSPData::getEntity(int index) const { return entity_list[index]; } void VBSPData::addModel(Model & newModel) { model_list.push_back(newModel); } const int VBSPData::getNumModels() const { return model_list.size(); } const Model & VBSPData::getModel(int index) const { return model_list[index]; } void VBSPData::addPlane(bsp::Plane & newPlane) { plane_list.push_back(newPlane); } const int VBSPData::getNumPlanes() const { return plane_list.size(); } const bsp::Plane & VBSPData::getPlane(int index) const { return plane_list[index]; } void VBSPData::addVertex(osg::Vec3f & newVertex) { // Scale the vertex from inches up to meter scale vertex_list.push_back(newVertex * 0.0254f); } const int VBSPData::getNumVertices() const { return vertex_list.size(); } const osg::Vec3f & VBSPData::getVertex(int index) const { return vertex_list[index]; } void VBSPData::addEdge(Edge & newEdge) { edge_list.push_back(newEdge); } const int VBSPData::getNumEdges() const { return edge_list.size(); } const Edge & VBSPData::getEdge(int index) const { return edge_list[index]; } void VBSPData::addSurfaceEdge(int & newSurfEdge) { surface_edge_list.push_back(newSurfEdge); } const int VBSPData::getNumSurfaceEdges() const { return surface_edge_list.size(); } const int VBSPData::getSurfaceEdge(int index) const { return surface_edge_list[index]; } void VBSPData::addFace(Face & newFace) { face_list.push_back(newFace); } const int VBSPData::getNumFaces() const { return face_list.size(); } const Face & VBSPData::getFace(int index) const { return face_list[index]; } void VBSPData::addTexInfo(TexInfo & newTexInfo) { texinfo_list.push_back(newTexInfo); } const int VBSPData::getNumTexInfos() const { return texinfo_list.size(); } const TexInfo & VBSPData::getTexInfo(int index) const { return texinfo_list[index]; } void VBSPData::addTexData(TexData & newTexData) { texdata_list.push_back(newTexData); } const int VBSPData::getNumTexDatas() const { return texdata_list.size(); } const TexData & VBSPData::getTexData(int index) const { return texdata_list[index]; } void VBSPData::addTexDataString(std::string & newTexDataString) { texdata_string_list.push_back(newTexDataString); } const int VBSPData::getNumTexDataStrings() const { return texdata_string_list.size(); } const std::string & VBSPData::getTexDataString(int index) const { return texdata_string_list[index]; } void VBSPData::addDispInfo(DisplaceInfo & newDispInfo) { dispinfo_list.push_back(newDispInfo); } const int VBSPData::getNumDispInfos() const { return dispinfo_list.size(); } const DisplaceInfo & VBSPData::getDispInfo(int index) const { return dispinfo_list[index]; } void VBSPData::addDispVertex(DisplacedVertex & newDispVertex) { displaced_vertex_list.push_back(newDispVertex); } const int VBSPData::getNumDispVertices() const { return displaced_vertex_list.size(); } const DisplacedVertex & VBSPData::getDispVertex(int index) const { return displaced_vertex_list[index]; } void VBSPData::addStaticPropModel(std::string & newModel) { static_prop_model_list.push_back(newModel); } const int VBSPData::getNumStaticPropModels() const { return static_prop_model_list.size(); } const std::string & VBSPData::getStaticPropModel(int index) const { return static_prop_model_list[index]; } void VBSPData::addStaticProp(StaticPropV4 & newProp) { StaticProp newPropV5; // Create a version 5 static prop and copy the data from the given // version 4 prop into it memcpy(&newPropV5, &newProp, sizeof(StaticPropV4)); newPropV5.forced_fade_scale = 1.0; // Add the new prop to the list static_prop_list.push_back(newPropV5); } void VBSPData::addStaticProp(StaticProp & newProp) { static_prop_list.push_back(newProp); } const int VBSPData::getNumStaticProps() const { return static_prop_list.size(); } const StaticProp & VBSPData::getStaticProp(int index) const { return static_prop_list[index]; } void VBSPData::addStateSet(StateSet * stateSet) { state_set_list.push_back(stateSet); } const int VBSPData::getNumStateSets() const { return state_set_list.size(); } StateSet * VBSPData::getStateSet(int index) const { return state_set_list[index].get(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/Q3BSPReader.cpp0000644000175000017500000004602013151044751025250 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Q3BSPReader.h" #include "Q3BSPLoad.h" #ifndef GL_RGBA8 #define GL_RGBA8 0x8058 #endif using namespace bsp; Q3BSPReader::Q3BSPReader() { root_node = NULL; } bool Q3BSPReader::readFile(const std::string& file, const osgDB::ReaderWriter::Options* options) { std::string ext = osgDB::getLowerCaseFileExtension(file); Q3BSPLoad load_data; load_data.Load(file,8); osg::Geode* geode = convertFromBSP(load_data, options); if (!geode) return false; //osg::StateSet* state_set=geode->getOrCreateStateSet(); //state_set->setMode(osg::CullFace::BACK,osg::StateAttribute::ON); root_node = geode; return true; } osg::ref_ptr Q3BSPReader::getRootNode() { return root_node; } enum BSP_FACE_TYPE { bspPolygonFace=1, bspPatch, bspMeshFace, bspBillboard }; class BSP_VERTEX { public: osg::Vec3f m_position; float m_decalS, m_decalT; float m_lightmapS, m_lightmapT; BSP_VERTEX operator+(const BSP_VERTEX & rhs) const { BSP_VERTEX result; result.m_position=m_position+rhs.m_position; result.m_decalS=m_decalS+rhs.m_decalS; result.m_decalT=m_decalT+rhs.m_decalT; result.m_lightmapS=m_lightmapS+rhs.m_lightmapS; result.m_lightmapT=m_lightmapT+rhs.m_lightmapT; return result; } BSP_VERTEX operator*(const float rhs) const { BSP_VERTEX result; result.m_position=m_position*rhs; result.m_decalS=m_decalS*rhs; result.m_decalT=m_decalT*rhs; result.m_lightmapS=m_lightmapS*rhs; result.m_lightmapT=m_lightmapT*rhs; return result; } }; //every patch (curved surface) is split into biquadratic (3x3) patches class BSP_BIQUADRATIC_PATCH { public: BSP_BIQUADRATIC_PATCH():m_vertices(32),m_indices(32) { } ~BSP_BIQUADRATIC_PATCH() { } bool Tessellate(int newTessellation,osg::Geometry* aGeometry); BSP_VERTEX m_controlPoints[9]; // Se accede a ellos en la carga protected: int m_tessellation; std::vector m_vertices; std::vector m_indices; //arrays for multi_draw_arrays std::vector m_trianglesPerRow; std::vector m_rowIndexPointers; }; //curved surface class BSP_PATCH { public: BSP_PATCH():m_quadraticPatches(32) { } ~BSP_PATCH() { } int m_textureIndex; int m_lightmapIndex; int m_width, m_height; int m_numQuadraticPatches; std::vector m_quadraticPatches; }; osg::Geode* Q3BSPReader::convertFromBSP( Q3BSPLoad& aLoadData, const osgDB::ReaderWriter::Options* options) const { std::vector texture_array; loadTextures(aLoadData,texture_array); std::vector lightmap_array; loadLightMaps(aLoadData,lightmap_array); osg::Geode* map_geode=new osg::Geode; // Convertir los vertices unsigned int num_load_vertices=aLoadData.m_loadVertices.size(); osg::Vec3Array* vertex_array = new osg::Vec3Array(num_load_vertices); osg::Vec2Array* text_decal_array = new osg::Vec2Array(num_load_vertices); osg::Vec2Array* text_lmap_array = new osg::Vec2Array(num_load_vertices); float scale = 0.0254; unsigned int i; for(i=0; iaddDrawable(mesh_geom); } for(i=0; iaddDrawable(polygon_geom); } for(i=0; i=0) { lightmap_texture=lightmap_array[current_face.m_lightmapIndex]; } else { lightmap_texture=lightmap_array[lightmap_array.size()-1]; } //Create space to hold quadratic patches int numPatchesWide=(current_patch.m_width-1)/2; int numPatchesHigh=(current_patch.m_height-1)/2; current_patch.m_numQuadraticPatches = numPatchesWide*numPatchesHigh; current_patch.m_quadraticPatches.resize(current_patch.m_numQuadraticPatches); //fill in the quadratic patches for(int y=0; ygetOrCreateStateSet(); if(texture) { stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); } if(lightmap_texture) { stateset->setTextureAttributeAndModes(1,lightmap_texture,osg::StateAttribute::ON); } //patch_group->addChild(map_geode); current_patch.m_quadraticPatches[y*numPatchesWide+x].Tessellate(8/*aCurveTessellation*/,patch_geom); map_geode->addDrawable(patch_geom); } } } //int num_primitive_sets=geom->getNumPrimitiveSets(); //const osg::BoundingSphere& bs=map_geom->getBound(); map_geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); return map_geode; } osg::Geometry* Q3BSPReader::createMeshFace( const BSP_LOAD_FACE& aLoadFace,const std::vector& aTextureArray, osg::Vec3Array& aVertexArray,std::vector& aIndices, osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords ) const { osg::Geometry* obj_geom = new osg::Geometry; osg::Vec3Array* obj_vertex_array = new osg::Vec3Array(aLoadFace.m_numMeshIndices, &(aVertexArray)[aLoadFace.m_firstVertexIndex] ); obj_geom->setVertexArray(obj_vertex_array); osg::DrawElementsUInt* face_indices = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, aLoadFace.m_numMeshIndices, &(aIndices)[0]+aLoadFace.m_firstMeshIndex ); obj_geom->addPrimitiveSet(face_indices); osg::Texture2D *texture=aTextureArray[aLoadFace.m_texture]; if(texture) { osg::StateSet* stateset = obj_geom->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON); osg::Vec2Array* obj_texcoords_array = new osg::Vec2Array(aLoadFace.m_numMeshIndices, &(aTextureDecalCoords)[aLoadFace.m_firstVertexIndex] ); obj_geom->setTexCoordArray(0,obj_texcoords_array); osg::Vec2Array* obj_lmapcoords_array = new osg::Vec2Array(aLoadFace.m_numMeshIndices, &(aTextureLMapCoords)[aLoadFace.m_firstVertexIndex] ); obj_geom->setTexCoordArray(1,obj_lmapcoords_array); } return obj_geom; } osg::Geometry* Q3BSPReader::createPolygonFace(const BSP_LOAD_FACE& aLoadFace,const std::vector& aTextureArray,const std::vector& aTextureLMapArray, osg::Vec3Array& aVertexArray, osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords ) const { osg::Texture2D *texture=aTextureArray[aLoadFace.m_texture]; osg::Geometry* polygon_geom = new osg::Geometry; polygon_geom->setVertexArray(&aVertexArray); polygon_geom->setTexCoordArray(0, &aTextureDecalCoords); polygon_geom->setTexCoordArray(1, &aTextureLMapCoords); osg::DrawArrays* face_indices = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN, aLoadFace.m_firstVertexIndex, aLoadFace.m_numVertices ); osg::StateSet* stateset = polygon_geom->getOrCreateStateSet(); if(texture) { stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); if(aLoadFace.m_lightmapIndex>=0) { texture=aTextureLMapArray[aLoadFace.m_lightmapIndex]; if(texture) { stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON); } } else { texture=aTextureLMapArray[aTextureLMapArray.size()-1]; if(texture) { stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON); } } } else { osg::PolygonMode* polygon_mode=new osg::PolygonMode; polygon_mode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE); stateset->setAttributeAndModes(polygon_mode, osg::StateAttribute::ON); } polygon_geom->addPrimitiveSet(face_indices); return polygon_geom; } bool Q3BSPReader::loadTextures( const Q3BSPLoad& aLoadData, std::vector& aTextureArray) const { int num_textures=aLoadData.m_loadTextures.size(); int i; for(i=0;i image = osgDB::readRefImageFile(tgaExtendedName); if (!image) { image = osgDB::readRefImageFile(jpgExtendedName); if (!image) { aTextureArray.push_back(NULL); continue; //? } } osg::Texture2D* texture= new osg::Texture2D; texture->setImage(image.get()); texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state. texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT); texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT); aTextureArray.push_back(texture); } return true; } bool Q3BSPReader::loadLightMaps( const Q3BSPLoad& aLoadData, std::vector& aTextureArray) const { int num_textures=aLoadData.m_loadLightmaps.size(); int i; for(i=0;isetImage(128,128,1,GL_RGBA8,GL_RGB,GL_UNSIGNED_BYTE,data,osg::Image::USE_NEW_DELETE); osg::Texture2D* texture= new osg::Texture2D; texture->setImage(image); texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state. texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR_MIPMAP_LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT); texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT); aTextureArray.push_back(texture); } // A continuacin, aado el blanco osg::Image* image=new osg::Image; unsigned char *data=new unsigned char[3]; for(int whiteidx=0;whiteidx<3;whiteidx++) { data[whiteidx]=255; } image->setImage(1,1,1,GL_RGBA8,GL_RGB,GL_UNSIGNED_BYTE,data,osg::Image::USE_NEW_DELETE); osg::Texture2D* texture= new osg::Texture2D; texture->setImage(image); texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state. texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR_MIPMAP_LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT); texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT); aTextureArray.push_back(texture); return true; } //Tessellate a biquadratic patch bool BSP_BIQUADRATIC_PATCH::Tessellate(int newTessellation,osg::Geometry* aGeometry) { m_tessellation=newTessellation; float px, py; BSP_VERTEX temp[3]; m_vertices.resize((m_tessellation+1)*(m_tessellation+1)); for(int v=0; v<=m_tessellation; ++v) { px=(float)v/m_tessellation; m_vertices[v]=m_controlPoints[0]*((1.0f-px)*(1.0f-px))+ m_controlPoints[3]*((1.0f-px)*px*2)+ m_controlPoints[6]*(px*px); } for(int u=1; u<=m_tessellation; ++u) { py=(float)u/m_tessellation; temp[0]=m_controlPoints[0]*((1.0f-py)*(1.0f-py))+ m_controlPoints[1]*((1.0f-py)*py*2)+ m_controlPoints[2]*(py*py); temp[1]=m_controlPoints[3]*((1.0f-py)*(1.0f-py))+ m_controlPoints[4]*((1.0f-py)*py*2)+ m_controlPoints[5]*(py*py); temp[2]=m_controlPoints[6]*((1.0f-py)*(1.0f-py))+ m_controlPoints[7]*((1.0f-py)*py*2)+ m_controlPoints[8]*(py*py); for(int v=0; v<=m_tessellation; ++v) { px=(float)v/m_tessellation; m_vertices[u*(m_tessellation+1)+v]=temp[0]*((1.0f-px)*(1.0f-px))+ temp[1]*((1.0f-px)*px*2)+ temp[2]*(px*px); } } //Create indices m_indices.resize(m_tessellation*(m_tessellation+1)*2); int row; for(row=0; rowsetVertexArray(patch_vertex_array); aGeometry->setTexCoordArray(0,patch_textcoord_array); aGeometry->setTexCoordArray(1,patch_lmapcoord_array); for(row=0; rowaddPrimitiveSet(face_indices); } return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPGeometry.cpp0000644000175000017500000005704413151044751025573 0ustar albertoalberto #include #include #include #include "VBSPGeometry.h" using namespace osg; using namespace bsp; VBSPGeometry::VBSPGeometry(VBSPData * bspData) { // Keep track of the bsp data, as it has all of the data lists that we // need bsp_data = bspData; // Create arrays for the vertex attributes vertex_array = new Vec3Array(); normal_array = new Vec3Array(); texcoord_array = new Vec2Array(); // Create a primitive set for drawing variable length primitives (VBSP // primitives are only guaranteed to be convex polygons) primitive_set = new DrawArrayLengths(PrimitiveSet::POLYGON); // Create a second set of arrays for displacement surfaces disp_vertex_array = new Vec3Array(); disp_normal_array = new Vec3Array(); disp_texcoord_array = new Vec2Array(); disp_vertex_attr_array = new Vec4Array(); // Create a second primitive set for drawing indexed triangles, which is // the quickest method for drawing the displacement surfaces disp_primitive_set = new DrawElementsUInt(PrimitiveSet::TRIANGLES); } VBSPGeometry::~VBSPGeometry() { } bool VBSPGeometry::doesEdgeExist(int row, int col, int direction, int vertsPerEdge) { // See if there is an edge on the displacement surface from the given // vertex in the given direction (we only need to know the vertices // indices, because all displacement surfaces are tessellated in the // same way) switch (direction) { case 0: // False if we're on the left edge, otherwise true if ((row - 1) < 0) return false; else return true; case 1: // False if we're on the top edge, otherwise true if ((col + 1) >= vertsPerEdge) return false; else return true; case 2: // False if we're on the right edge, otherwise true if ((row + 1) >= vertsPerEdge) return false; else return true; case 3: // False if we're on the bottom edge, otherwise true if ((col - 1) < 0) return false; else return true; default: return false; } } osg::Vec3 VBSPGeometry::getNormalFromEdges(int row, int col, unsigned char edgeBits, int firstVertex, int vertsPerEdge) { osg::Vec3 * vertexData; osg::Vec3 * surfaceVerts; osg::Vec3 finalNormal; osg::Vec3 v1, v2, v3; osg::Vec3 e1, e2; osg::Vec3 tempNormal; int normalCount; // Constants for direction. If the bit is set in the edgeBits, then // there is an edge connected to the current vertex in that direction const unsigned char NEG_X = 1 << 0; const unsigned char POS_Y = 1 << 1; const unsigned char POS_X = 1 << 2; const unsigned char NEG_Y = 1 << 3; // Constants for quadrants. If both bits are set, then there are // exactly two triangles in that quadrant const unsigned char QUAD_1 = POS_X | POS_Y; const unsigned char QUAD_2 = NEG_X | POS_Y; const unsigned char QUAD_3 = NEG_X | NEG_Y; const unsigned char QUAD_4 = POS_X | NEG_Y; // Grab the vertex data from the displaced vertex array (if there's a // better way to randomly access the data in this array, I'm all ears) vertexData = (osg::Vec3 *)disp_vertex_array->getDataPointer(); // Move to the surface we're interested in, and start counting vertices // from there surfaceVerts = &vertexData[firstVertex]; // Start with no normals computed finalNormal.set(0.0, 0.0, 0.0); normalCount = 0; // The process is fairly simple. For all four quadrants surrounding // the vertex, check each quadrant to see if there are triangles there. // If so, calculate the normals of the two triangles in that quadrant, and // add them to the final normal. When fininshed, scale the final normal // based on the number of contributing triangle normals // Check quadrant 1 (+X,+Y) if ((edgeBits & QUAD_1) == QUAD_1) { // First triangle v1 = surfaceVerts[(col+1) * vertsPerEdge + row]; v2 = surfaceVerts[col * vertsPerEdge + row]; v3 = surfaceVerts[col * vertsPerEdge + (row+1)]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; // Second triangle v1 = surfaceVerts[(col+1) * vertsPerEdge + row]; v2 = surfaceVerts[col * vertsPerEdge + (row+1)]; v3 = surfaceVerts[(col+1) * vertsPerEdge + (row+1)]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; } // Check quadrant 2 (-X,+Y) if ((edgeBits & QUAD_2) == QUAD_2) { // First triangle v1 = surfaceVerts[(col+1) * vertsPerEdge + (row-1)]; v2 = surfaceVerts[col * vertsPerEdge + (row-1)]; v3 = surfaceVerts[col * vertsPerEdge + row]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; // Second triangle v1 = surfaceVerts[(col+1) * vertsPerEdge + (row-1)]; v2 = surfaceVerts[col * vertsPerEdge + row]; v3 = surfaceVerts[(col+1) * vertsPerEdge + row]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; } // Check quadrant 3 (-X,-Y) if ((edgeBits & QUAD_3) == QUAD_3) { // First triangle v1 = surfaceVerts[col * vertsPerEdge + (row-1)]; v2 = surfaceVerts[(col-1) * vertsPerEdge + (row-1)]; v3 = surfaceVerts[(col-1) * vertsPerEdge + row]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; // Second triangle v1 = surfaceVerts[col * vertsPerEdge + (row-1)]; v2 = surfaceVerts[(col-1) * vertsPerEdge + row]; v3 = surfaceVerts[col * vertsPerEdge + row]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; } // Check quadrant 4 (+X,-Y) if ((edgeBits & QUAD_4) == QUAD_4) { // First triangle v1 = surfaceVerts[col * vertsPerEdge + row]; v2 = surfaceVerts[(col-1) * vertsPerEdge + row]; v3 = surfaceVerts[(col-1) * vertsPerEdge + (row+1)]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; // Second triangle v1 = surfaceVerts[col * vertsPerEdge + row]; v2 = surfaceVerts[(col-1) * vertsPerEdge + (row+1)]; v3 = surfaceVerts[col * vertsPerEdge + (row+1)]; e1 = v1 - v2; e2 = v3 - v2; tempNormal = e2 ^ e1; tempNormal.normalize(); finalNormal += tempNormal; normalCount++; } // Scale the final normal according to how many triangle normals are // contributing finalNormal *= (1.0f / (float)normalCount); return finalNormal; } void VBSPGeometry::createDispSurface(Face & face, DisplaceInfo & dispInfo) { TexInfo currentTexInfo; TexData currentTexData; Vec3 texU; float texUOffset; float texUScale; Vec3 texV; float texVOffset; float texVScale; int i, j; unsigned int k; double dist, minDist; int minIndex = 0; osg::Vec3 temp; int edgeIndex; int currentSurfEdge; Edge currentEdge; osg::Vec3 currentVertex; osg::Vec3 vertices[4]; unsigned int firstVertex; int numEdgeVertices; double subdivideScale; osg::Vec3 leftEdge, rightEdge; osg::Vec3 leftEdgeStep, rightEdgeStep; osg::Vec3 leftEnd, rightEnd; osg::Vec3 leftRightSeg, leftRightStep; unsigned int dispVertIndex; DisplacedVertex dispVertInfo; osg::Vec3 flatVertex, dispVertex; unsigned int index; osg::Vec3 normal; float u, v; osg::Vec2 texCoord; float alphaBlend; unsigned char edgeBits; // Get the texture info for this face currentTexInfo = bsp_data->getTexInfo(face.texinfo_index); currentTexData = bsp_data->getTexData(currentTexInfo.texdata_index); // Get the texture vectors and offsets. These are used to calculate // texture coordinates texU.set(currentTexInfo.texture_vecs[0][0], currentTexInfo.texture_vecs[0][1], currentTexInfo.texture_vecs[0][2]); texUOffset = currentTexInfo.texture_vecs[0][3]; texV.set(currentTexInfo.texture_vecs[1][0], currentTexInfo.texture_vecs[1][1], currentTexInfo.texture_vecs[1][2]); texVOffset = currentTexInfo.texture_vecs[1][3]; // Scale the texture vectors from inches to meters texU *= 39.37f; texV *= 39.37f; // Get the size of the texture involved, as the planar texture projection // assumes non-normalized texture coordinates texUScale = 1.0f / (float)currentTexData.texture_width; texVScale = 1.0f / (float)currentTexData.texture_height; // Get the first edge index edgeIndex = face.first_edge; // Get the base vertices for this face for (i = 0; i < face.num_edges; i++) { // Look up the edge specified by the surface edge index, the // index might be negative (see below), so take the absolute // value currentSurfEdge = bsp_data->getSurfaceEdge(edgeIndex); currentEdge = bsp_data->getEdge(abs(currentSurfEdge)); // The sign of the surface edge index specifies which vertex is // "first" for this face. A negative index means the edge should // be flipped, and the second vertex treated as the first if (currentSurfEdge < 0) currentVertex = bsp_data->getVertex(currentEdge.vertex[1]); else currentVertex = bsp_data->getVertex(currentEdge.vertex[0]); // Add the vertex to the array vertices[i] = currentVertex; // Move on to the next vertex edgeIndex++; } // Rotate the base coordinates for the surface until the first vertex // matches the start position minDist = 1.0e9; for (i = 0; i < 4; i++) { // Calculate the distance of the start position from this vertex dist = (vertices[i] - dispInfo.start_position * 0.0254f).length(); // If this is the smallest distance we've seen, remember it if (dist < minDist) { minDist = dist; minIndex = i; } } // Rotate the displacement surface quad until we get the starting vertex // in the 0th position for (i = 0; i < minIndex; i++) { temp = vertices[0]; vertices[0] = vertices[1]; vertices[1] = vertices[2]; vertices[2] = vertices[3]; vertices[3] = temp; } // Calculate the vectors for the left and right edges of the surface // (remembering that the surface is wound clockwise) leftEdge = vertices[1] - vertices[0]; rightEdge = vertices[2] - vertices[3]; // Calculate the number of vertices along each edge of the surface numEdgeVertices = (1 << dispInfo.power) + 1; // Calculate the subdivide scale, which will tell us how far apart to // put each vertex (relative to the length of the surface's edges) subdivideScale = 1.0 / (double)(numEdgeVertices - 1); // Calculate the step size between vertices on the left and right edges leftEdgeStep = leftEdge * subdivideScale; rightEdgeStep = rightEdge * subdivideScale; // Remember the first vertex index in the vertex array firstVertex = disp_vertex_array->size(); // Generate the displaced vertices (this technique comes from the // Source SDK) for (i = 0; i < numEdgeVertices; i++) { // Calculate the two endpoints for this section of the surface leftEnd = leftEdgeStep * (double) i; leftEnd += vertices[0]; rightEnd = rightEdgeStep * (double) i; rightEnd += vertices[3]; // Now, get the vector from left to right, and subdivide it as well leftRightSeg = rightEnd - leftEnd; leftRightStep = leftRightSeg * subdivideScale; // Generate the vertices for this section for (j = 0; j < numEdgeVertices; j++) { // Get the displacement info for this vertex dispVertIndex = dispInfo.disp_vert_start; dispVertIndex += i * numEdgeVertices + j; dispVertInfo = bsp_data->getDispVertex(dispVertIndex); // Calculate the flat vertex flatVertex = leftEnd + (leftRightStep * (double) j); // Calculate the displaced vertex dispVertex = dispVertInfo.displace_vec * (dispVertInfo.displace_dist * 0.0254); dispVertex += flatVertex; // Add the vertex to the displaced vertex array disp_vertex_array->push_back(dispVertex); // Calculate the texture coordinates for this vertex. Texture // coordinates are calculated using a planar projection, so we need // to use the non-displaced vertex position here u = texU * flatVertex + texUOffset; u *= texUScale; v = texV * flatVertex + texVOffset; v *= texVScale; texCoord.set(u, v); // Add the texture coordinate to the array disp_texcoord_array->push_back(texCoord); // Get the texture blend parameter for this vertex as well, and // assign it as the alpha channel for the primary vertex color. // We'll use a combiner operation to do the texture blending alphaBlend = dispVertInfo.alpha_blend / 255.0; disp_vertex_attr_array->push_back( osg::Vec4f(1.0, 1.0, 1.0, 1.0 - alphaBlend)); } } // Calculate normals at each vertex (this is adapted from the Source SDK, // including the two helper functions) for (i = 0; i < numEdgeVertices; i++) { for (j = 0; j < numEdgeVertices; j++) { // See which of the 4 possible edges (left, up, right, or down) are // incident on this vertex edgeBits = 0; for (k = 0; k < 4; k++) { if (doesEdgeExist(j, i, k, numEdgeVertices)) edgeBits |= 1 << k; } // Calculate the normal based on the adjacent edges normal = getNormalFromEdges(j, i, edgeBits, firstVertex, numEdgeVertices); // Add the normal to the normal array disp_normal_array->push_back(normal); } } // Now, triangulate the surface (this technique comes from the Source SDK) for (i = 0; i < numEdgeVertices-1; i++) { for (j = 0; j < numEdgeVertices-1; j++) { // Get the current vertex index (local to this surface) index = i * numEdgeVertices + j; // See if this index is odd if ((index % 2) == 1) { // Add the vertex offset (so we reference this surface's // vertices in the array) index += firstVertex; // Create two triangles on this vertex from top-left to // bottom-right disp_primitive_set->push_back(index); disp_primitive_set->push_back(index + 1); disp_primitive_set->push_back(index + numEdgeVertices); disp_primitive_set->push_back(index + 1); disp_primitive_set->push_back(index + numEdgeVertices + 1); disp_primitive_set->push_back(index + numEdgeVertices); } else { // Add the vertex offset (so we reference this surface's // vertices in the array) index += firstVertex; // Create two triangles on this vertex from bottom-left to // top-right disp_primitive_set->push_back(index); disp_primitive_set->push_back(index + numEdgeVertices + 1); disp_primitive_set->push_back(index + numEdgeVertices); disp_primitive_set->push_back(index); disp_primitive_set->push_back(index + 1); disp_primitive_set->push_back(index + numEdgeVertices + 1); } } } } void VBSPGeometry::addFace(int faceIndex) { Face currentFace; Edge currentEdge; DisplaceInfo currentDispInfo; TexInfo currentTexInfo; TexData currentTexData; Vec3 normal; int edgeIndex; int i; int currentSurfEdge; Vec3 currentVertex; Vec3 texU; float texUOffset; float texUScale; Vec3 texV; float texVOffset; float texVScale; float u, v; Vec2f texCoord; // Make sure this face is not "on node" (an internal node of the BSP tree). // These faces are not used for visible geometry currentFace = bsp_data->getFace(faceIndex); // See if this is a displacement surface if (currentFace.dispinfo_index != -1) { // Get the displacement info currentDispInfo = bsp_data->getDispInfo(currentFace.dispinfo_index); // Generate the displacement surface createDispSurface(currentFace, currentDispInfo); } else { // Get the face normal, using the plane information normal = bsp_data->getPlane(currentFace.plane_index).plane_normal; if (currentFace.plane_side != 0) normal = -normal; // Get the texture info and data structures currentTexInfo = bsp_data->getTexInfo(currentFace.texinfo_index); currentTexData = bsp_data->getTexData(currentTexInfo.texdata_index); // Get the texture vectors and offsets. These are used to calculate // texture coordinates texU.set(currentTexInfo.texture_vecs[0][0], currentTexInfo.texture_vecs[0][1], currentTexInfo.texture_vecs[0][2]); texUOffset = currentTexInfo.texture_vecs[0][3]; texV.set(currentTexInfo.texture_vecs[1][0], currentTexInfo.texture_vecs[1][1], currentTexInfo.texture_vecs[1][2]); texVOffset = currentTexInfo.texture_vecs[1][3]; // Scale the texture vectors from inches to meters texU *= 39.37f; texV *= 39.37f; // Get the texture size, as the planar texture projection results in // non-normalized texture coordinates texUScale = 1.0f / (float)currentTexData.texture_width; texVScale = 1.0f / (float)currentTexData.texture_height; // Start with the last edge index, because we need to switch from // clockwise winding (DirectX) to counter-clockwise winding (OpenGL) edgeIndex = currentFace.first_edge + currentFace.num_edges - 1; // Set the length of this primitive on the primitive set primitive_set->push_back(currentFace.num_edges); // Iterate over the edges in this face, and extract the vertex data for (i = 0; i < currentFace.num_edges; i++) { // Look up the edge specified by the surface edge index, the // index might be negative (see below), so take the absolute // value currentSurfEdge = bsp_data->getSurfaceEdge(edgeIndex); currentEdge = bsp_data->getEdge(abs(currentSurfEdge)); // The sign of the surface edge index specifies which vertex is // "first" for this face. A negative index means the edge should // be flipped, and the second vertex treated as the first if (currentSurfEdge < 0) currentVertex = bsp_data->getVertex(currentEdge.vertex[1]); else currentVertex = bsp_data->getVertex(currentEdge.vertex[0]); // Add the vertex to the array vertex_array->push_back(currentVertex); // Set the normal normal_array->push_back(normal); // Calculate the texture coordinates for this vertex u = texU * currentVertex + texUOffset; u *= texUScale; v = texV * currentVertex + texVOffset; v *= texVScale; texCoord.set(u, v); // Add the texture coordinate to the array texcoord_array->push_back(texCoord); // Move on to the next (previous?) vertex edgeIndex--; } } } ref_ptr VBSPGeometry::createGeometry() { ref_ptr rootGroup; ref_ptr geode; ref_ptr geometry; Vec4f color; ref_ptr colorArray; // Create the root group (we'll attach everything to this group and // return it) rootGroup = new Group(); // Create a geode for the geometries geode = new Geode(); rootGroup->addChild(geode.get()); // See if there are any regular (non-displaced) faces to render if (primitive_set->size() > 0) { // Create a geometry object for the regular surfaces geometry = new Geometry(); // Add the vertex attributes geometry->setVertexArray(vertex_array.get()); geometry->setNormalArray(normal_array.get(), Array::BIND_PER_VERTEX); geometry->setTexCoordArray(0, texcoord_array.get()); // Add an overall color color.set(1.0, 1.0, 1.0, 1.0); colorArray = new Vec4Array(1, &color); geometry->setColorArray(colorArray.get(), Array::BIND_OVERALL); // Add our primitive set to the geometry geometry->addPrimitiveSet(primitive_set.get()); // Add the geometry to the geode geode->addDrawable(geometry.get()); // Now, stripify the geode to convert the POLYGON primitives to // triangle strips osgUtil::TriStripVisitor tsv; geode->accept(tsv); tsv.stripify(); } // Now do the same for the displacement surfaces (if any) if (disp_primitive_set->size() > 0) { // Create a geometry object for the regular surfaces geometry = new Geometry(); // Add the vertex attributes geometry->setVertexArray(disp_vertex_array.get()); geometry->setNormalArray(disp_normal_array.get(), Array::BIND_PER_VERTEX); geometry->setColorArray(disp_vertex_attr_array.get(), Array::BIND_PER_VERTEX); geometry->setTexCoordArray(0, disp_texcoord_array.get()); geometry->setTexCoordArray(1, disp_texcoord_array.get()); // Add our primitive set to the geometry geometry->addPrimitiveSet(disp_primitive_set.get()); // Add the geometry to the geode geode->addDrawable(geometry.get()); } // Return the root group return rootGroup; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/ReaderWriterBSP.h0000644000175000017500000000071613151044751025710 0ustar albertoalberto#ifndef __READERWRITER_VBSP_H_ #define __READERWRITER_VBSP_H_ #include #include namespace bsp { class ReaderWriterBSP : public osgDB::ReaderWriter { public: virtual const char* className() const; virtual bool acceptsExtension(const std::string& extension) const; virtual ReadResult readNode(const std::string& file, const Options* options) const; }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/BITSET.h0000644000175000017500000000161313151044751023733 0ustar albertoalberto////////////////////////////////////////////////////////////////////////////////////////// // BITSET.h // class declaration for set of bits to represent many true/falses // You may use this code however you wish, but if you do, please credit me and // provide a link to my website in a readme file or similar // Downloaded from: www.paulsprojects.net // Created: 8th August 2002 ////////////////////////////////////////////////////////////////////////////////////////// #ifndef BITSET_H #define BITSET_H #include class BITSET { public: BITSET() : m_numBytes(0) {} ~BITSET() { } bool Init(int numberOfBits); void ClearAll(); void SetAll(); void Clear(int bitNumber); void Set(int bitNumber); unsigned char IsSet(int bitNumber) const; protected: int m_numBytes; //size of bits array unsigned char * m_bits_aux; std::vector m_bits; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPReader.cpp0000644000175000017500000011520313151044751025172 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "VBSPReader.h" #include "VBSPEntity.h" using namespace bsp; using namespace osg; using namespace osgDB; // strcasecmp for MSVC #ifdef _MSC_VER #define strcasecmp _stricmp #endif VBSPReader::VBSPReader() { // Start with no root node root_node = NULL; // Create the map data object bsp_data = new VBSPData(); // No string table yet texdata_string = NULL; texdata_string_table = NULL; num_texdata_string_table_entries = 0; } VBSPReader::~VBSPReader() { // Clean up the texdata strings and such delete [] texdata_string; delete [] texdata_string_table; } void VBSPReader::processEntities(std::istream & str, int offset, int length) { char * entities; char * startPtr; char * endPtr; int numEntities; int i; std::string entityStr; size_t entityLen; // Create the string entities = new char[length]; memset(entities, 0, length * sizeof(char)); // Seek to the Entities lump str.seekg(offset); // Read the entities string str.read((char *) entities, sizeof(char) * length); // Count the number of entities startPtr = entities; endPtr = strchr(entities, '}'); numEntities = 0; while ((startPtr != NULL) && (endPtr != NULL)) { // Increment the count numEntities++; // Advance the pointers startPtr = strchr(endPtr, '{'); if (startPtr != NULL) endPtr = strchr(startPtr, '}'); } // Parse the entities startPtr = entities; endPtr = strchr(entities, '}'); for (i = 0; i < numEntities; i++) { // Get the length of this entity entityLen = endPtr - startPtr + 1; // Create the entity list entry and copy the entity information entityStr = std::string(startPtr, entityLen); bsp_data->addEntity(entityStr); // Advance the pointers startPtr = strchr(endPtr, '{'); if (startPtr != NULL) endPtr = strchr(startPtr, '}'); } // Free up the original entities string delete [] entities; } void VBSPReader::processModels(std::istream & str, int offset, int length) { int numModels; int i; Model * models; // Calculate the number of models numModels = length / sizeof(Model); // Seek to the Models lump str.seekg(offset); // Read the models models = new Model[numModels]; str.read((char *) models, sizeof(Model) * numModels); // Add the models to the model list for (i = 0; i < numModels; i++) bsp_data->addModel(models[i]); // Clean up delete [] models; } void VBSPReader::processPlanes(std::istream & str, int offset, int length) { int numPlanes; int i; Plane * planes; // Calculate the number of planes numPlanes = length / sizeof(Plane); // Seek to the Planes lump str.seekg(offset); // Read the planes planes = new Plane[numPlanes]; str.read((char *) planes, sizeof(Plane) * numPlanes); // Add the planes to the plane list for (i = 0; i < numPlanes; i++) bsp_data->addPlane(planes[i]); // Clean up delete [] planes; } void VBSPReader::processVertices(std::istream & str, int offset, int length) { int numVertices; int i; Vec3f * vertices; // Calculate the number of vertices numVertices = length / 3 / sizeof(float); // Seek to the Vertices lump str.seekg(offset); // Read the vertex vertices = new Vec3f[numVertices]; str.read((char *) vertices, sizeof(Vec3f) * numVertices); // Add it the vertices to the list for (i = 0; i < numVertices; i++) bsp_data->addVertex(vertices[i]); // Clean up delete [] vertices; } void VBSPReader::processEdges(std::istream & str, int offset, int length) { int numEdges; int i; Edge * edges; // Calculate the number of edges numEdges = length / sizeof(Edge); // Seek to the Edges lump str.seekg(offset); // Read the edges edges = new Edge[numEdges]; str.read((char *) edges, sizeof(Edge) * numEdges); // Add the edges to the edge list for (i = 0; i < numEdges; i++) bsp_data->addEdge(edges[i]); // Clean up delete [] edges; } void VBSPReader::processSurfEdges(std::istream & str, int offset, int length) { int numSurfEdges; int i; int * surfEdges; // Calculate the number of edges numSurfEdges = length / sizeof(int); // Seek to the SurfEdges lump str.seekg(offset); // Read the surface edges surfEdges = new int[numSurfEdges]; str.read((char *) surfEdges, sizeof(int) * numSurfEdges); // Add the surface edges to the surface edge list for (i = 0; i < numSurfEdges; i++) bsp_data->addSurfaceEdge(surfEdges[i]); // Clean up delete [] surfEdges; } void VBSPReader::processFaces(std::istream & str, int offset, int length) { int numFaces; int i; Face * faces; // Calculate the number of faces numFaces = length / sizeof(Face); // Seek to the Faces lump str.seekg(offset); // Read the faces faces = new Face[numFaces]; str.read((char *) faces, sizeof(Face) * numFaces); // Add the faces to the face list for (i = 0; i < numFaces; i++) bsp_data->addFace(faces[i]); // Clean up delete [] faces; } void VBSPReader::processTexInfo(std::istream & str, int offset, int length) { int numTexInfos; int i; TexInfo * texinfos; // Calculate the number of texinfos numTexInfos = length / sizeof(TexInfo); // Seek to the TexInfo lump str.seekg(offset); // Read in the texinfo entries texinfos = new TexInfo[numTexInfos]; str.read((char *) texinfos, sizeof(TexInfo) * numTexInfos); // Add the texinfo entries to the texinfo list for (i = 0; i < numTexInfos; i++) bsp_data->addTexInfo(texinfos[i]); // Clean up delete [] texinfos; } void VBSPReader::processTexData(std::istream & str, int offset, int length) { int numTexDatas; int i; TexData * texdatas; // Calculate the number of texdatas numTexDatas = length / sizeof(TexData); // Seek to the TexData lump str.seekg(offset); // Read in the texdata entries texdatas = new TexData[numTexDatas]; str.read((char *) texdatas, sizeof(TexData) * numTexDatas); // Add the texdata entries to the texdata list for (i = 0; i < numTexDatas; i++) bsp_data->addTexData(texdatas[i]); // Clean up delete [] texdatas; } void VBSPReader::processTexDataStringTable(std::istream & str, int offset, int length) { int i; int index; std::string texStr; // Calculate the number of table entries num_texdata_string_table_entries = length / sizeof(int); // Create the texdata string table texdata_string_table = new int[num_texdata_string_table_entries]; // Seek to the TexDataStringTable lump str.seekg(offset); // Read in the texdata_string_table str.read((char *) texdata_string_table, sizeof(int) * num_texdata_string_table_entries); // If we have a texdata string loaded, parse the texdata strings now if (texdata_string != NULL) { for (i = 0; i < num_texdata_string_table_entries; i++) { // Add the strings from the string data, using the string table // to index it index = texdata_string_table[i]; texStr = std::string(&texdata_string[index]); bsp_data->addTexDataString(texStr); } } } void VBSPReader::processTexDataStringData(std::istream & str, int offset, int length) { int i; int index; std::string texStr; // Create the buffer to hold the texdata string texdata_string = new char[length]; memset(texdata_string, 0, length * sizeof(char)); // Seek to the TexDataStringData lump str.seekg(offset); // Read the entire texdata string (this string is actually a // NULL-delimited list of strings) str.read((char *) texdata_string, sizeof(char) * length); // If we have a string table loaded, parse the texdata strings now // (if not, num_texdata_string_table_entries will be zero and we'll // skip this loop) for (i = 0; i < num_texdata_string_table_entries; i++) { // Add the strings from the string data, using the string table // to index it index = texdata_string_table[i]; texStr = std::string(&texdata_string[index]); bsp_data->addTexDataString(texStr); } } void VBSPReader::processDispInfo(std::istream & str, int offset, int length) { int numDispInfos; int i; DisplaceInfo * dispinfos; // Calculate the number of dispinfos numDispInfos = length / sizeof(DisplaceInfo); // Seek to the DisplaceInfo lump str.seekg(offset); // Read in the dispinfo entries dispinfos = new DisplaceInfo[numDispInfos]; str.read((char *) dispinfos, sizeof(DisplaceInfo) * numDispInfos); // Add the dispinfo entries to the displace info list for (i = 0; i < numDispInfos; i++) bsp_data->addDispInfo(dispinfos[i]); // Clean up delete [] dispinfos; } void VBSPReader::processDispVerts(std::istream & str, int offset, int length) { int numDispVerts; int i; DisplacedVertex * dispverts; // Calculate the number of displaced vertices numDispVerts = length / sizeof(DisplacedVertex); // Seek to the DispVert lump str.seekg(offset); // Read in the displaced vertices dispverts = new DisplacedVertex[numDispVerts]; str.read((char *) dispverts, sizeof(DisplacedVertex) * numDispVerts); // Add the displaced vertices to the displaced vertex list for (i = 0; i < numDispVerts; i++) bsp_data->addDispVertex(dispverts[i]); // Clean up delete [] dispverts; } void VBSPReader::processGameData(std::istream & str, int offset, int length) { GameHeader gameHeader; GameLump * gameLumps; int i; // Read the header str.seekg(offset); str.read((char *) &gameHeader, sizeof(GameHeader)); // Create and read in the game lump list gameLumps = new GameLump[gameHeader.num_lumps]; str.read((char *) gameLumps, sizeof(GameLump) * gameHeader.num_lumps); // Iterate over the game lumps for (i = 0; i < gameHeader.num_lumps; i++) { // See if this is a lump we're interested in if (gameLumps[i].lump_id == STATIC_PROP_ID) { processStaticProps(str, gameLumps[i].lump_offset, gameLumps[i].lump_length, gameLumps[i].lump_version); } } // Clean up delete [] gameLumps; } void VBSPReader::processStaticProps(std::istream & str, int offset, int length, int lumpVersion) { StaticPropModelNames sprpModelNames; char modelName[130]; std::string modelStr; int i; StaticPropLeaves sprpLeaves; StaticProps sprpHeader; StaticPropV4 sprp4; StaticProp sprp5; // First, read the static prop models dictionary str.seekg(offset); str.read((char *) &sprpModelNames, sizeof(StaticPropModelNames)); for (i = 0; i < sprpModelNames.num_model_names; i++) { str.read(modelName, 128); modelName[128] = 0; modelStr = std::string(modelName); bsp_data->addStaticPropModel(modelStr); } // Next, skip over the static prop leaf array str.read((char *) &sprpLeaves, sizeof(StaticPropLeaves)); str.seekg(sprpLeaves.num_leaf_entries * sizeof(unsigned short), std::istream::cur); // Finally, read in the static prop entries str.read((char *) &sprpHeader, sizeof(StaticProps)); for (i = 0; i < sprpHeader.num_static_props; i++) { // The version number determines how much we read for each prop if (lumpVersion == 4) { // Read the static prop and add it to the bsp data str.read((char *) &sprp4, sizeof(StaticPropV4)); bsp_data->addStaticProp(sprp4); } else if (lumpVersion == 5) { // Read the static prop and add it to the bsp data str.read((char *) &sprp5, sizeof(StaticProp)); bsp_data->addStaticProp(sprp5); } } } std::string VBSPReader::getToken(std::string str, const char * delim, size_t & index) { std::string token; size_t end = std::string::npos; // Look for the first non-occurrence of the delimiters size_t start = str.find_first_not_of(delim, index); if (start != std::string::npos) { // From there, look for the first occurrence of a delimiter end = str.find_first_of(delim, start+1); if (end != std::string::npos) { // Found a delimiter, so grab the string in between token = str.substr(start, end-start); } else { // Ran off the end of the string, so just grab everything from // the first good character token = str.substr(start); } } else { // No token to be found token = ""; } // Update the index (in case we want to keep looking for tokens in this // string) if (end != std::string::npos) index = end+1; else index = std::string::npos; // Return the token return token; } ref_ptr VBSPReader::readTextureFile(std::string textureName) { std::string texFile; std::string texPath; osg::ref_ptr texImage; osg::ref_ptr texture; // Find the texture's image file texFile = std::string(textureName) + ".vtf"; texPath = findDataFile(texFile, CASE_INSENSITIVE); // If we don't find it right away, check in a "materials" subdirectory if (texPath.empty()) { texFile = "materials/" + std::string(textureName) + ".vtf"; texPath = findDataFile(texFile, CASE_INSENSITIVE); // Check up one directory if we don't find it here (the map file is // usually located in the "maps" directory, adjacent to the materials // directory) if (texPath.empty()) { texFile = "../materials/" + std::string(textureName) + ".vtf"; texPath = findDataFile(texFile, CASE_INSENSITIVE); } } // If we found the file, read it, otherwise bail if (!texPath.empty()) { texImage = readRefImageFile(texPath); // If we got the image, create the texture attribute if (texImage != NULL) { // Create the texture if (texImage->t() == 1) { texture = new Texture1D(texImage.get()); } else if (texImage->r() == 1) { texture = new Texture2D(texImage.get()); } else { texture = new Texture3D(texImage.get()); } // Set texture attributes texture->setWrap(Texture::WRAP_S, Texture::REPEAT); texture->setWrap(Texture::WRAP_T, Texture::REPEAT); texture->setWrap(Texture::WRAP_R, Texture::REPEAT); texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR); texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR); } else { // We were unable to find the texture file OSG_WARN << "Couldn't find texture " << textureName; OSG_WARN << std::endl; // No texture texture = NULL; } } else { // We were unable to find the texture file OSG_WARN << "Couldn't find texture " << textureName; OSG_WARN << std::endl; // No texture texture = NULL; } return texture; } ref_ptr VBSPReader::readMaterialFile(std::string materialName) { std::string mtlFileName; std::string mtlPath; osgDB::ifstream * mtlFile; std::string line; std::string::size_type start = std::string::npos; std::string token; bool found = false; ref_ptr stateSet; std::string shaderName; std::string texName; std::string tex2Name; ref_ptr texture; ref_ptr texture2; ref_ptr combiner0; ref_ptr combiner1; ref_ptr material; ref_ptr blend; bool translucent; double alpha; // Find the material file mtlFileName = std::string(materialName) + ".vmt"; mtlPath = findDataFile(mtlFileName, CASE_INSENSITIVE); // If we don't find it right away, check in a "materials" subdirectory if (mtlPath.empty()) { mtlFileName = "materials/" + std::string(materialName) + ".vmt"; mtlPath = findDataFile(mtlFileName, CASE_INSENSITIVE); // Check up one directory if we don't find it here (the map file is // usually located in the "maps" directory, adjacent to the materials // directory) if (mtlPath.empty()) { mtlFileName = "../materials/" + std::string(materialName) + ".vmt"; mtlPath = findDataFile(mtlFileName, CASE_INSENSITIVE); } } // See if we found the file if (!mtlPath.empty()) { // Try to open the file, bail out if we fail mtlFile = new osgDB::ifstream(mtlPath.c_str(), std::ifstream::in); if (!mtlFile) return NULL; } else { // Didn't find the material file, so return NULL OSG_WARN << "Can't find material " << materialName << std::endl; return NULL; } // First, look for the shader name found = false; while ((!found) && (!mtlFile->eof())) { // Read a line from the file std::getline(*mtlFile, line); // Try to find the shader name start = 0; token = getToken(line, " \t\n\r\"", start); // If we got something, it must be the shader if ((!token.empty()) && (token.compare(0, 2, "//") != 0)) { shaderName = token; found = true; } } // If we didn't find a shader, this isn't a valid material file if (!found) { mtlFile->close(); OSG_WARN << "Material " << materialName << " isn't valid."; OSG_WARN << std::endl; return NULL; } // No textures loaded yet texture = NULL; texture2 = NULL; // Assume no transparency unless the properties say otherwise translucent = false; // Assume fully opaque alpha = 1.0; // Read the material properties next while (!mtlFile->eof()) { // Get the next line std::getline(*mtlFile, line); // Look for tokens starting at the beginning start = 0; token = getToken(line, " \t\n\r\"", start); while ((!token.empty()) && (token.compare(0, 2, "//") != 0)) { if (equalCaseInsensitive(token, "$basetexture")) { // Get the base texture name token = getToken(line, " \t\n\r\"", start); // Read the texture if (!token.empty()) texture = readTextureFile(token); } else if (equalCaseInsensitive(token, "$basetexture2")) { // Get the second base texture name token = getToken(line, " \t\n\r\"", start); // Read the texture if (!token.empty()) texture2 = readTextureFile(token); } else if ((equalCaseInsensitive(token, "$translucent")) || (equalCaseInsensitive(token, "$alphatest"))) { // Get the translucency setting token = getToken(line, " \t\n\r\"", start); // Interpret the setting if ((token == "1") || (token == "true")) translucent = true; } else if (equalCaseInsensitive(token, "$alpha")) { // Get the translucency setting token = getToken(line, " \t\n\r\"", start); // Interpret the setting if (!token.empty()) { alpha = osg::asciiToDouble(token.c_str()); } } // Try the next token token = getToken(line, " \t\n\r\"", start); } } // Start with no StateSet (in case the stuff below fails) stateSet = NULL; // Check the shader's name if (equalCaseInsensitive(shaderName, "WorldVertexTransition")) { // Make sure we have both textures if (texture.valid() && texture2.valid()) { // Create a StateSet for the following state stateSet = new osg::StateSet(); // Attach the two textures stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON); stateSet->setTextureAttributeAndModes(1, texture2.get(), osg::StateAttribute::ON); // On the first texture unit, set up a combiner operation to // interpolate between the textures on units 0 and 1, using // the fragment's primary alpha color as the interpolation // parameter (NOTE: we need ARB_texture_env_crossbar for this) combiner0 = new osg::TexEnvCombine(); combiner0->setConstantColor(osg::Vec4f(1.0, 1.0, 1.0, 1.0)); combiner0->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); combiner0->setSource0_RGB(osg::TexEnvCombine::TEXTURE0); combiner0->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); combiner0->setSource1_RGB(osg::TexEnvCombine::TEXTURE1); combiner0->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); combiner0->setSource2_RGB(osg::TexEnvCombine::PRIMARY_COLOR); combiner0->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); combiner0->setCombine_Alpha(osg::TexEnvCombine::REPLACE); combiner0->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); combiner0->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); combiner0->setScale_RGB(1.0); combiner0->setScale_Alpha(1.0); stateSet->setTextureAttributeAndModes(0, combiner0.get(), osg::StateAttribute::ON); // On the second texture unit, do a typical modulate operation // between the interpolated texture color from the previous // unit and the fragment's primary (lit) RGB color. Force the // alpha to be 1.0, since this HL2 shader is never transparent combiner1 = new osg::TexEnvCombine(); combiner1->setConstantColor(osg::Vec4f(1.0, 1.0, 1.0, 1.0)); combiner1->setCombine_RGB(osg::TexEnvCombine::MODULATE); combiner1->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); combiner1->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); combiner1->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR); combiner1->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); combiner1->setCombine_Alpha(osg::TexEnvCombine::REPLACE); combiner1->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); combiner1->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); combiner1->setScale_RGB(1.0); combiner1->setScale_Alpha(1.0); stateSet->setTextureAttributeAndModes(1, combiner1.get(), osg::StateAttribute::ON); // Add a material to the state set material = new Material(); material->setAmbient(Material::FRONT_AND_BACK, Vec4(1.0, 1.0, 1.0, 1.0) ); material->setDiffuse(Material::FRONT_AND_BACK, Vec4(1.0, 1.0, 1.0, 1.0) ); material->setSpecular(Material::FRONT_AND_BACK, Vec4(0.0, 0.0, 0.0, 1.0) ); material->setShininess(Material::FRONT_AND_BACK, 1.0); material->setEmission(Material::FRONT_AND_BACK, Vec4(0.0, 0.0, 0.0, 1.0) ); material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); stateSet->setAttributeAndModes(material.get(), StateAttribute::ON); } } else if (equalCaseInsensitive(shaderName, "UnlitGeneric")) { // Create the StateSet stateSet = new StateSet(); // Disable lighting on this StateSet stateSet->setMode(GL_LIGHTING, StateAttribute::OFF); // Add the texture attribute (or disable texturing if no base texture) if (texture != NULL) { stateSet->setTextureAttributeAndModes(0, texture.get(), StateAttribute::ON); stateSet->setTextureAttributeAndModes(0, new TexEnv(TexEnv::MODULATE), StateAttribute::ON); // See if the material is translucent if (translucent) { // Create and apply a blend function attribute to the // state set blend = new BlendFunc(BlendFunc::SRC_ALPHA, BlendFunc::ONE_MINUS_SRC_ALPHA); stateSet->setAttributeAndModes(blend.get(), StateAttribute::ON); // Set the state set's rendering hint to transparent stateSet->setRenderingHint(StateSet::TRANSPARENT_BIN); } } else { OSG_WARN << "No base texture for material " << materialName; OSG_WARN << std::endl; stateSet->setTextureMode(0, GL_TEXTURE_2D, StateAttribute::OFF); } } else { // All other shaders fall back to fixed function // TODO: LightMappedGeneric shader // Create the StateSet stateSet = new StateSet(); // Add a material to the state set material = new Material(); material->setAmbient(Material::FRONT_AND_BACK, Vec4(1.0, 1.0, 1.0, 1.0) ); material->setDiffuse(Material::FRONT_AND_BACK, Vec4(1.0, 1.0, 1.0, 1.0) ); material->setSpecular(Material::FRONT_AND_BACK, Vec4(0.0, 0.0, 0.0, 1.0) ); material->setShininess(Material::FRONT_AND_BACK, 1.0); material->setEmission(Material::FRONT_AND_BACK, Vec4(0.0, 0.0, 0.0, 1.0) ); material->setAlpha(Material::FRONT_AND_BACK, alpha); stateSet->setAttributeAndModes(material.get(), StateAttribute::ON); // Add the texture attribute (or disable texturing if no base texture) if (texture != NULL) { stateSet->setTextureAttributeAndModes(0, texture.get(), StateAttribute::ON); stateSet->setTextureAttributeAndModes(0, new TexEnv(TexEnv::MODULATE), StateAttribute::ON); // See if the material is translucent if (translucent) { // Create and apply a blend function attribute to the // state set blend = new BlendFunc(BlendFunc::SRC_ALPHA, BlendFunc::ONE_MINUS_SRC_ALPHA); stateSet->setAttributeAndModes(blend.get(), StateAttribute::ON); // Set the state set's rendering hint to transparent stateSet->setRenderingHint(StateSet::TRANSPARENT_BIN); } } else { OSG_WARN << "No base texture for material " << materialName; OSG_WARN << std::endl; stateSet->setTextureMode(0, GL_TEXTURE_2D, StateAttribute::OFF); } } // Close the file mtlFile->close(); // Return the resulting StateSet return stateSet; } void VBSPReader::createScene() { ref_ptr group; ref_ptr subGroup; TexData currentTexData; const char * texName; char currentTexName[256]; char prefix[64]; char * mtlPtr; char * tmpPtr; char tempTex[256]; std::string entityText; VBSPEntity * currentEntity; int i; ref_ptr stateSet; StaticProp staticProp; Matrixf transMat, rotMat; Quat yaw, pitch, roll; ref_ptr propXform; std::string propModel; std::string propFile; ref_ptr propNode; // Load the materials and create a StateSet for each one for (i = 0; i < bsp_data->getNumTexDatas(); i++) { // Get the texdata entry and texture name currentTexData = bsp_data->getTexData(i); texName = bsp_data-> getTexDataString(currentTexData.name_string_table_id).c_str(); strcpy(currentTexName, texName); // See if this is referring to an environment mapped material (we don't // handle this yet) sprintf(prefix, "maps/%s/", map_name.c_str()); if (strncmp(currentTexName, prefix, strlen(prefix)) == 0) { // This texture is referring to this map's PAK file, so it could // be an environment mapped texture (an existing material that is // modified by a cube map of the scene). If so, we just need to // get the base material name mtlPtr = currentTexName; mtlPtr += strlen(prefix); // Now, we're pointing at the path to the material itself, so copy // what we've got so far strcpy(tempTex, mtlPtr); // Now, we just need to trim the two or three cube map coordinates // from the end. // This isn't a perfect solution, but it should catch most cases. // The right way to do this would be to read the .vmt file from the // map's PAKFILE lump, and make use of the basetexture parameter in // it tmpPtr = strrchr(tempTex, '/'); mtlPtr = strrchr(tempTex, '_'); if ((mtlPtr != NULL) && (mtlPtr > tmpPtr)) *mtlPtr = 0; mtlPtr = strrchr(tempTex, '_'); if ((mtlPtr != NULL) && (mtlPtr > tmpPtr)) *mtlPtr = 0; mtlPtr = strrchr(tempTex, '_'); if ((mtlPtr != NULL) && (mtlPtr > tmpPtr)) *mtlPtr = 0; // That should be it, so make it the texture name strcpy(currentTexName, tempTex); } // Read the material for this geometry stateSet = readMaterialFile(currentTexName); // Whether we successfully created a StateSet or not, add it to the // bsp data list now bsp_data->addStateSet(stateSet.get()); } // Create the root group for the scene group = new Group(); // Iterate through the list of entities, and try to convert all the // visible entities to geometry for (i = 0; i < bsp_data->getNumEntities(); i++) { // Get the entity entityText = bsp_data->getEntity(i); currentEntity = new VBSPEntity(entityText, bsp_data.get()); // See if the entity is visible if (currentEntity->isVisible()) { // Create geometry for the entity subGroup = currentEntity->createGeometry(); // If the entity's geometry is valid, add it to the main group if (subGroup.valid()) group->addChild(subGroup.get()); } // Done with this entity delete currentEntity; } // Iterate through the list of static props, and add them to the scene // as well for (i = 0; i < bsp_data->getNumStaticProps(); i++) { // Get the static prop staticProp = bsp_data->getStaticProp(i); // Create a MatrixTransform for this prop (scale the position from // inches to meters) transMat.makeTranslate(staticProp.prop_origin * 0.0254); pitch.makeRotate(osg::DegreesToRadians(staticProp.prop_angles.x()), Vec3f(0.0, 1.0, 0.0)); yaw.makeRotate(osg::DegreesToRadians(staticProp.prop_angles.y()), Vec3f(0.0, 0.0, 1.0)); roll.makeRotate(osg::DegreesToRadians(staticProp.prop_angles.z()), Vec3f(1.0, 0.0, 0.0)); rotMat.makeRotate(roll * pitch * yaw); propXform = new MatrixTransform(); propXform->setMatrix(rotMat * transMat); // Load the prop's model propModel = bsp_data->getStaticPropModel(staticProp.prop_type); propNode = osgDB::readRefNodeFile(propModel); // If we loaded the prop correctly, add it to the scene if (propNode.valid()) { // Add the model to the transform node, and attach the transform // to the scene propXform->addChild(propNode.get()); group->addChild(propXform.get()); // Name the prop propXform->setName(std::string("prop_static:" + propModel)); } else { OSG_WARN << "Couldn't find static prop \"" << propModel; OSG_WARN << "\"." << std::endl; // Couldn't find the prop, so get rid of the transform node propXform = NULL; } } // Set the root node to the result root_node = group.get(); } bool VBSPReader::readFile(const std::string & file) { osgDB::ifstream * mapFile = 0; Header header; int i = 0; // Remember the map name map_name = getStrippedName(file); mapFile = new osgDB::ifstream(file.c_str(), std::ios::binary); if (!mapFile) return false; // Read the header mapFile->read((char *) &header, sizeof(Header)); // Load the bsp file lumps that we care about for (i = 0; i < MAX_LUMPS; i++) { if ((header.lump_table[i].file_offset != 0) && (header.lump_table[i].lump_length != 0)) { // Process the lump switch (i) { case ENTITIES_LUMP: processEntities(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case PLANES_LUMP: processPlanes(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case VERTICES_LUMP: processVertices(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case EDGES_LUMP: processEdges(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case SURFEDGES_LUMP: processSurfEdges(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case MODELS_LUMP: processModels(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case FACES_LUMP: processFaces(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case TEXINFO_LUMP: processTexInfo(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case TEXDATA_LUMP: processTexData(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case TEXDATA_STRING_TABLE_LUMP: processTexDataStringTable(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case TEXDATA_STRING_DATA_LUMP: processTexDataStringData(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case DISPINFO_LUMP: processDispInfo(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case DISP_VERTS_LUMP: processDispVerts(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; case GAME_LUMP: processGameData(*mapFile, header.lump_table[i].file_offset, header.lump_table[i].lump_length); break; } } } // Create the OSG scene from the BSP data createScene(); return true; } ref_ptr VBSPReader::getRootNode() { return root_node; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/ReaderWriterBSP.cpp0000644000175000017500000000627013151044751026244 0ustar albertoalberto#include #include #include #include #include #include "ReaderWriterBSP.h" #include "VBSPReader.h" #include "Q3BSPReader.h" using namespace bsp; using namespace osg; using namespace osgDB; // "VBSP" for Valve BSP files const int VBSP_MAGIC_NUMBER = (('P'<<24)+('S'<<16)+('B'<<8)+'V'); // "IBSP" for id (Quake 3) BSP files const int IBSP_MAGIC_NUMBER = (('P'<<24)+('S'<<16)+('B'<<8)+'I'); const char* ReaderWriterBSP::className() const { // Return a description of this class return "BSP File Reader"; } bool ReaderWriterBSP::acceptsExtension(const std::string& extension) const { // If the extension is empty or "bsp", we accept it return osgDB::equalCaseInsensitive(extension, "bsp") || extension.empty(); } ReaderWriter::ReadResult ReaderWriterBSP::readNode( const std::string& file, const ReaderWriter::Options* options) const { VBSPReader * vbspReader; Q3BSPReader * q3bspReader; ref_ptr result; osgDB::ifstream stream; int magicNumber; int version; // See if we handle this kind of file if (!acceptsExtension(osgDB::getFileExtension(file))) return ReadResult::FILE_NOT_HANDLED; // See if we can find the requested file std::string fileName = osgDB::findDataFile(file, options); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; // Open the file and read the magic number and version stream.open(fileName.c_str(), std::ios::binary); stream.read((char *) &magicNumber, sizeof(int)); stream.read((char *) &version, sizeof(int)); stream.close(); // See which kind of BSP file this is if ((magicNumber == VBSP_MAGIC_NUMBER) && (version >= 19) && (version <= 20)) { // Read the Valve file vbspReader = new VBSPReader(); if (vbspReader->readFile(fileName)) { // Get the results of our read result = vbspReader->getRootNode(); // Clean up the reader delete vbspReader; // Return the results return ReadResult(result.get()); } else { // Clean up the reader delete vbspReader; // Return the error return ReadResult::ERROR_IN_READING_FILE; } } else if ((magicNumber == IBSP_MAGIC_NUMBER) && (version == 0x2E)) { // Read the Quake 3 file q3bspReader = new Q3BSPReader(); if (q3bspReader->readFile(file, options)) { // Get the results of our read result = q3bspReader->getRootNode(); // Clean up the reader delete q3bspReader; // Return the results return ReadResult(result.get()); } else { // Clean up the reader delete q3bspReader; // Return the error return ReadResult::ERROR_IN_READING_FILE; } } return ReadResult::FILE_NOT_HANDLED; } REGISTER_OSGPLUGIN(bsp, ReaderWriterBSP) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/Q3BSPReader.h0000644000175000017500000000505313151044751024716 0ustar albertoalberto// El siguiente bloque ifdef muestra la forma estndar de crear macros que facilitan // la exportacin de archivos DLL. Todos los archivos de este archivo DLL se compilan con el smbolo Q3BSP_EXPORTS // definido en la lnea de comandos. Este smbolo no se debe definir en ningn proyecto // que utilice este archivo DLL. De este modo, otros proyectos cuyos archivos de cdigo fuente incluyan el archivo // interpreta que las funciones Q3BSP_API se importan de un archivo DLL, mientras que este archivo DLL interpreta los smbolos // definidos en esta macro como si fueran exportados. /* #ifdef Q3BSP_EXPORTS #define Q3BSP_API __declspec(dllexport) #else #define Q3BSP_API __declspec(dllimport) #endif // Clase exportada de q3bsp.dll class Q3BSP_API Cq3bsp { public: Cq3bsp(void); // TODO: agregar mtodos aqu. }; extern Q3BSP_API int nq3bsp; Q3BSP_API int fnq3bsp(void); */ #include #include #include #include #include "Q3BSPLoad.h" namespace bsp { class Q3BSPReader { public: Q3BSPReader(); bool readFile(const std::string& fileName, const osgDB::ReaderWriter::Options*); osg::ref_ptr getRootNode(); private: osg::ref_ptr root_node; osg::Geode* convertFromBSP(Q3BSPLoad& aLoadData, const osgDB::ReaderWriter::Options*) const; osg::Geometry* createMeshFace( const BSP_LOAD_FACE& aLoadFace, const std::vector& aTextureArray, osg::Vec3Array& aVertexArray, std::vector& aIndices, osg::Vec2Array& aTextureDecalCoords, osg::Vec2Array& aTextureLMapCoords) const; osg::Geometry* createPolygonFace( const BSP_LOAD_FACE& aLoadFace, const std::vector& aTextureArray, const std::vector& aTextureLMapArray, osg::Vec3Array& aVertexArray, osg::Vec2Array& aTextureDecalCoords, osg::Vec2Array& aTextureLMapCoords) const; bool loadTextures( const Q3BSPLoad& aLoadData, std::vector& aTextureArray) const; bool loadLightMaps( const Q3BSPLoad& aLoadData, std::vector& aTextureArray) const; }; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/Q3BSPLoad.h0000644000175000017500000000704013151044751024371 0ustar albertoalberto #ifndef Q3BSPLOAD_H #define Q3BSPLOAD_H #include #include #include #include #include namespace bsp { //Directory entry in header class BSP_DIRECTORY_ENTRY { public: int m_offset; int m_length; }; //Types of directory entry enum BSP_DIRECTORY_ENTRY_TYPE { bspEntities=0, bspTextures, bspPlanes, bspNodes, bspLeaves, bspLeafFaces, bspLeafBrushes, bspModels, bspBrushes, bspBrushSides, bspVertices, bspMeshIndices, bspEffect, bspFaces, bspLightmaps, bspLightVols, bspVisData }; //BSP file header class BSP_HEADER { public: char m_string[4]; int m_version; BSP_DIRECTORY_ENTRY m_directoryEntries[17]; }; //vertex as found in file class BSP_LOAD_VERTEX { public: osg::Vec3f m_position; float m_decalS, m_decalT; float m_lightmapS, m_lightmapT; osg::Vec3f m_normal; unsigned char m_color[4]; }; struct BSP_LoadPlane { osg::Vec3f m_Normal; float m_Dist; }; //face as found in the file class BSP_LOAD_FACE { public: int m_texture; int m_effect; // No se usa int m_type; int m_firstVertexIndex; int m_numVertices; unsigned int m_firstMeshIndex; unsigned int m_numMeshIndices; int m_lightmapIndex; int m_lightmapStart[2]; // No se usa int m_lightmapSize[2]; // No se usa //VECTOR3D m_lightmapOrigin; // No se usa //VECTOR3D m_sTangent, m_tTangent; // No se usa //VECTOR3D m_normal; // No se usa osg::Vec3f m_lightmapOrigin; // No se usa osg::Vec3f m_sTangent, m_tTangent; // No se usa osg::Vec3f m_normal; // No se usa int m_patchSize[2]; }; //texture as found in file class BSP_LOAD_TEXTURE { public: char m_name[64]; int m_flags, m_contents; //unknown, no se usa }; //lightmap as found in file class BSP_LOAD_LIGHTMAP { public: unsigned char m_lightmapData[128*128*3]; }; //leaf of bsp tree as found in file class BSP_LOAD_LEAF { public: int m_cluster; //cluster index for visdata int m_area; //areaportal area, No se usa int m_mins[3]; //min x,y,z (bounding box) int m_maxs[3]; int m_firstLeafFace; //first index in leafFaces array int m_numFaces; int m_firstLeafBrush; //first index into leaf brushes array, No se usa int m_numBrushes; // No se usa }; //node of BSP tree class BSP_NODE { public: int m_planeIndex; int m_front, m_back; //child nodes int m_mins[3]; //min x,y,z (bounding box) No se usa int m_maxs[3]; // No se usa }; //VIS data table class BSP_VISIBILITY_DATA { public: int m_numClusters; int m_bytesPerCluster; std::vector m_bitset; }; class Q3BSPLoad { public: bool Load(const std::string& filename, int curveTessellation); void LoadVertices(std::ifstream& aFile); void LoadFaces(std::ifstream& aFile, int curveTessellation); void LoadTextures(std::ifstream& aFile); void LoadLightmaps(std::ifstream& aFile); void LoadBSPData(std::ifstream& aFile); std::string m_entityString; //header BSP_HEADER m_header; // Load Data std::vector m_loadVertices; std::vector m_loadMeshIndices; std::vector m_loadFaces; std::vector m_loadTextures; std::vector m_loadLightmaps; std::vector m_loadLeaves; std::vector m_loadLeafFaces; std::vector m_loadPlanes; std::vector m_loadNodes; BSP_VISIBILITY_DATA m_loadVisibilityData; }; } #endif // Q3BSPLOAD_H OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPEntity.cpp0000644000175000017500000004427213151044751025253 0ustar albertoalberto #include "VBSPEntity.h" #include "VBSPGeometry.h" #include #include #include #include #include #include #include #include using namespace bsp; using namespace osg; using namespace osgDB; // strcasecmp for MSVC #ifdef _MSC_VER #define strcasecmp _stricmp #endif VBSPEntity::VBSPEntity(std::string & entityText, VBSPData * bspData) { // Save a handle to the bsp data, as we'll need this to construct the // entity bsp_data = bspData; // Assume we're not visible at first entity_visible = false; // Assume no transform entity_transformed = false; // No model (external or internal) yet entity_model_index = -1; entity_model.clear(); // Don't know the class yet entity_class = ENTITY_OTHER; // Parse the entity's text to gather parameters parseParameters(entityText); } VBSPEntity::~VBSPEntity() { } void VBSPEntity::processWorldSpawn() { // World spawn is definitely visible entity_visible = true; // World spawn is always centered at the origin, so there's no need for // a transform entity_transformed = false; // The world spawn's internal model index is always zero entity_model_index = 0; } void VBSPEntity::processEnv() { // We don't support these entities yet, so leave them invisible } void VBSPEntity::processFuncBrush() { // These entities are usually transformed entity_transformed = true; // Get the internal model index for this entity EntityParameters::iterator param = entity_parameters.find("model"); if (param != entity_parameters.end()) { // Get the model number std::string value = (*param).second; // Skip the leading asterisk (internal models are denoted with a // leading asterisk), and then parse the model number if (value[0] == '*') { value = value.substr(1, std::string::npos); entity_model_index = atoi(value.c_str()); // Make the entity visible entity_visible = true; } else { // This shouldn't happen (brush entities don't reference // external models). Leave the entity invisible in this case entity_visible = false; } } else { // We can't locate the model for this entity, so leave it invisible entity_visible = false; } // Get the origin and angles for this entity param = entity_parameters.find("origin"); if (param != entity_parameters.end()) { // Get the origin parameter's value std::string value = (*param).second; // Parse the value into a vector entity_origin = getVector(value); } param = entity_parameters.find("angles"); if (param != entity_parameters.end()) { // Get the origin parameter's value std::string value = (*param).second; // Parse the value into a vector entity_angles = getVector(value); } } void VBSPEntity::processProp() { // These entities are visible entity_visible = true; // These entities are usually transformed entity_transformed = true; // Get the model we need to load for this entity EntityParameters::iterator param = entity_parameters.find("model"); if (param != entity_parameters.end()) { // Get the model parameter's value entity_model = (*param).second; } // Get the origin and angles for this entity param = entity_parameters.find("origin"); if (param != entity_parameters.end()) { // Get the origin parameter's value std::string value = (*param).second; // Parse the value into a vector entity_origin = getVector(value); } param = entity_parameters.find("angles"); if (param != entity_parameters.end()) { // Get the origin parameter's value std::string value = (*param).second; // Parse the value into a vector entity_angles = getVector(value); } } void VBSPEntity::processInfoDecal() { // We don't support these entities yet, so leave them invisible } void VBSPEntity::processItem() { // We don't support these entities yet, so leave them invisible } Vec3f VBSPEntity::getVector(std::string str) { float x, y, z; // Look for the first non-whitespace std::string::size_type start = str.find_first_not_of(" \t\r\n", 0); // Look for the first whitespace after this std::string::size_type end = str.find_first_of(" \t\r\n", start); if ((end > start) && (start != std::string::npos)) x = osg::asciiToFloat(str.substr(start, end-start).c_str()); else return Vec3f(); // Look for the next non-whitespace start = str.find_first_not_of(" \t\r\n", end+1); // Look for the first whitespace after this end = str.find_first_of(" \t\r\n", start); if ((end > start) && (start != std::string::npos)) y = osg::asciiToFloat(str.substr(start, end-start).c_str()); else return Vec3f(); // Look for the next non-whitespace start = str.find_first_not_of(" \t\r\n", end+1); // Look for the first whitespace after this end = str.find_first_of(" \t\r\n", start); if (end == std::string::npos) end = str.length(); if ((end > start) && (start != std::string::npos)) z = osg::asciiToFloat(str.substr(start, end-start).c_str()); else return Vec3f(); // If we get this far, return the vector that we parsed return Vec3f(x, y, z); } std::string VBSPEntity::getToken(std::string str, size_t & index) { std::string::size_type end = std::string::npos; std::string token; // Look for the first quotation mark std::string::size_type start = str.find_first_of("\"", index); if (start != std::string::npos) { // From there, look for the next occurrence of a delimiter start++; end = str.find_first_of("\"", start); if (end != std::string::npos) { // Found a delimiter, so grab the string in between token = str.substr(start, end-start); } else { // Ran off the end of the string, so just grab everything from // the first good character token = str.substr(start); } } else { // No token to be found token.clear(); } // Update the index (in case we want to keep looking for tokens in this // string) if (end != std::string::npos) index = end+1; else index = std::string::npos; // Return the token return token; } void VBSPEntity::parseParameters(std::string & entityText) { // Create a string stream on the entity text std::istringstream str(entityText, std::istringstream::in); // Iterate over the parameters while (!str.eof()) { // Get the next line of text std::string line; std::getline(str, line); // Look for the first quotation mark on the line size_t start = 0; std::string token = getToken(line, start); // If we have a valid token it will be the parameter name (the key), // look for a second token, which will be the parameter's value while (!token.empty()) { // Save the token as the key std::string key = token; // Get the next token start++; token = getToken(line, start); // See if the token is valid if (!token.empty()) { // This token is the value, create an entity parameter from // these two strings and add it to our parameters map EntityParameter param(key, token); entity_parameters.insert(param); } } } // Now that we have all of the parameters, figure out what kind of entity // this is EntityParameters::iterator param = entity_parameters.find("classname"); // See if we found the class if (param == entity_parameters.end()) { // We need the class to be able to do anything with this entity return; } // Get the class name and process the entity appropriately class_name = (*param).second; if (class_name.compare("worldspawn") == 0) { // This is the entity that represents the main geometry of the map // (the terrain and much of the static geometry) entity_class = ENTITY_WORLDSPAWN; processWorldSpawn(); } else if (class_name.compare(0, 3, "env") == 0) { // This is an environmental effect (such as a fire or dust cloud) entity_class = ENTITY_ENV; processEnv(); } else if ((class_name.compare("func_brush") == 0) || (class_name.compare("func_illusionary") == 0) || (class_name.compare("func_wall_toggle") == 0) || (class_name.compare("func_breakable") == 0)) { // This is secondary map geometry, created along with the main // map geometry (not an external model) entity_class = ENTITY_FUNC_BRUSH; processFuncBrush(); } else if (class_name.compare(0, 4, "prop") == 0) { // This is a "prop", an external model placed somewhere in the // scene entity_class = ENTITY_PROP; processProp(); } else if (class_name.compare("infodecal") == 0) { // This is a decal, which applies a texture to some surface in the // scene entity_class = ENTITY_INFO_DECAL; processInfoDecal(); } else if (class_name.compare(0, 4, "item") == 0) { // This is an "item". Like a prop, these are external models // placed in the scene, but the specific model is determined // directly by the entity's class. In HL2, these entities are // useable by the player (ammunition and health packs are examples) entity_class = ENTITY_ITEM; processItem(); } } ref_ptr VBSPEntity::createBrushGeometry() { int i; int numGeoms; VBSPGeometry ** vbspGeomList; Model currentModel; Face currentFace; TexInfo currentTexInfo; TexData currentTexData; const char * texName; char currentTexName[256]; int currentGeomIndex; VBSPGeometry * currentGeom; ref_ptr entityGroup; ref_ptr geomGroup; std::stringstream groupName; // Create a list of VBSPGeometry objects for each texdata entry in the // scene. These objects will hold the necessary geometry data until we // convert them back into OSG geometry objects. We potentially will need // one for each state set in the map numGeoms = bsp_data->getNumStateSets(); vbspGeomList = new VBSPGeometry *[numGeoms]; // Initialize the list to all NULL for now. We'll create the geometry // objects as we need them memset(vbspGeomList, 0, sizeof(VBSPGeometry *) * numGeoms); // Get this entity's internal model from the bsp data currentModel = bsp_data->getModel(entity_model_index); // Iterate over the face list and assign faces to the appropriate geometry // objects for (i = 0; i < currentModel.num_faces; i++) { // Get the current face currentFace = bsp_data->getFace(currentModel.first_face + i); // Get the texdata used by this face currentTexInfo = bsp_data->getTexInfo(currentFace.texinfo_index); currentTexData = bsp_data->getTexData(currentTexInfo.texdata_index); // Get the texture name texName = bsp_data-> getTexDataString(currentTexData.name_string_table_id).c_str(); strcpy(currentTexName, texName); // See if this is a non-drawable surface if ((strcasecmp(currentTexName, "tools/toolsareaportal") != 0) && (strcasecmp(currentTexName, "tools/toolsblocklos") != 0) && (strcasecmp(currentTexName, "tools/toolsblockbullets") != 0) && (strcasecmp(currentTexName, "tools/toolsblocklight") != 0) && (strcasecmp(currentTexName, "tools/toolsclip") != 0) && (strcasecmp(currentTexName, "tools/toolscontrolclip") != 0) && (strcasecmp(currentTexName, "tools/toolsdotted") != 0) && (strcasecmp(currentTexName, "tools/toolshint") != 0) && (strcasecmp(currentTexName, "tools/toolsinvisible") != 0) && (strcasecmp(currentTexName, "tools/toolsinvisibleladder") != 0) && (strcasecmp(currentTexName, "tools/toolsnodraw") != 0) && (strcasecmp(currentTexName, "tools/toolsnpcclip") != 0) && (strcasecmp(currentTexName, "tools/toolsoccluder") != 0) && (strcasecmp(currentTexName, "tools/toolsorigin") != 0) && (strcasecmp(currentTexName, "tools/toolsskip") != 0) && (strcasecmp(currentTexName, "tools/toolsskybox") != 0) && (strcasecmp(currentTexName, "tools/toolsskyfog") != 0) && (strcasecmp(currentTexName, "tools/toolstrigger") != 0)) { // Get or create the corresponding VBSPGeometry object from the // list currentGeomIndex = currentTexInfo.texdata_index; currentGeom = vbspGeomList[currentGeomIndex]; if (currentGeom == NULL) { // Create the geometry object vbspGeomList[currentGeomIndex] = new VBSPGeometry(bsp_data); currentGeom = vbspGeomList[currentGeomIndex]; } // Add the face to the appropriate VBSPGeometry object currentGeom->addFace(currentModel.first_face + i); } } // Create a top-level group to hold the geometry objects if (entity_transformed) { // Create a matrix transform MatrixTransform * entityXform = new MatrixTransform(); // Set it up with the entity's transform information (scale the // position from inches to meters) Matrixf transMat, rotMat; Quat roll, yaw, pitch; transMat.makeTranslate(entity_origin * 0.0254); pitch.makeRotate(osg::DegreesToRadians(entity_angles.x()), Vec3f(0.0, 1.0, 0.0)); yaw.makeRotate(osg::DegreesToRadians(entity_angles.y()), Vec3f(0.0, 0.0, 1.0)); roll.makeRotate(osg::DegreesToRadians(entity_angles.z()), Vec3f(1.0, 0.0, 0.0)); rotMat.makeRotate(roll * pitch * yaw); // Set the transform matrix entityXform->setMatrix(rotMat * transMat); // Use the transform node as the main entity group entityGroup = entityXform; } else { // Create a group to represent the entire entity entityGroup = new Group(); } // Iterate over the geometry array and convert each geometry object // into OSG geometry for (i = 0; i < numGeoms; i++) { // Get the next geometry object (if any) currentGeom = vbspGeomList[i]; if (currentGeom != NULL) { // Convert the BSP geometry to OSG geometry geomGroup = currentGeom->createGeometry(); // Make sure the geometry converted properly if (geomGroup.valid()) { // Set this group's state set geomGroup->setStateSet(bsp_data->getStateSet(i)); // Add the geometry group to the entity group entityGroup->addChild(geomGroup.get()); } } } // Name the entity group groupName << class_name << ":" << entity_model_index; entityGroup->setName(groupName.str()); // Return the group we created return entityGroup; } ref_ptr VBSPEntity::createModelGeometry() { std::string modelFile; ref_ptr modelNode; ref_ptr entityGroup; // Try to load the model modelNode = osgDB::readRefNodeFile(entity_model); if (modelNode.valid()) { // Create a group and add the model to it if (entity_transformed) { // Create a matrix transform MatrixTransform * entityXform = new MatrixTransform(); // Set it up with the entity's transform information (scale // the position from inches to meters) Matrixf transMat, rotMat; Quat roll, yaw, pitch; transMat.makeTranslate(entity_origin * 0.0254); pitch.makeRotate(osg::DegreesToRadians(entity_angles.x()), Vec3f(0.0, 1.0, 0.0)); yaw.makeRotate(osg::DegreesToRadians(entity_angles.y()), Vec3f(0.0, 0.0, 1.0)); roll.makeRotate(osg::DegreesToRadians(entity_angles.z()), Vec3f(1.0, 0.0, 0.0)); rotMat.makeRotate(roll * pitch * yaw); // Set the transform matrix entityXform->setMatrix(rotMat * transMat); // Use the transform node as the main entity group entityGroup = entityXform; } else { // Create a group to represent the entire entity entityGroup = new Group(); } // Add the model node to the group entityGroup->addChild(modelNode.get()); // Set the group's name entityGroup->setName(class_name + std::string(":") + entity_model); } else { OSG_WARN << "Couldn't find prop \"" << entity_model << "\"."; OSG_WARN << std::endl; // Leave the group empty (no model to show) entityGroup = NULL; } return entityGroup; } EntityClass VBSPEntity::getClass() { return entity_class; } bool VBSPEntity::isVisible() { return entity_visible; } ref_ptr VBSPEntity::createGeometry() { // If we're not a visible entity, we have no geometry if (!entity_visible) return NULL; // Create the geometry for the entity based on the class if ((entity_class == ENTITY_WORLDSPAWN) || (entity_class == ENTITY_FUNC_BRUSH)) { return createBrushGeometry(); } else if (entity_class == ENTITY_PROP) { return createModelGeometry(); } // If we get here, we don't handle this kind of entity (yet) return NULL; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPReader.h0000644000175000017500000001514113151044751024637 0ustar albertoalberto#ifndef __VBSP_READER_H_ #define __VBSP_READER_H_ #include #include #include #include #include #include #include #include "VBSPData.h" namespace bsp { // The magic number for a Valve BSP file is 'VBSP' in little-endian // order const int MAGIC_NUMBER = (('P'<<24)+('S'<<16)+('B'<<8)+'V'); enum LumpType { ENTITIES_LUMP, PLANES_LUMP, TEXDATA_LUMP, VERTICES_LUMP, VISIBILITY_LUMP, NODES_LUMP, TEXINFO_LUMP, FACES_LUMP, LIGHTING_LUMP, OCCLUSION_LUMP, LEAFS_LUMP, UNUSED_LUMP_11, EDGES_LUMP, SURFEDGES_LUMP, MODELS_LUMP, WORLD_LIGHTS_LUMP, LEAF_FACES_LUMP, LEAF_BRUSHES_LUMP, BRUSHES_LUMP, BRUSH_SIDES_LUMP, AREAS_LUMP, AREA_PORTALS_LUMP, PORTALS_LUMP, CLUSTERS_LUMP, PORTAL_VERTS_LUMP, CLUSTER_PORTALS_LUMP, DISPINFO_LUMP, ORIGINAL_FACES_LUMP, UNUSED_LUMP_28, PHYS_COLLIDE_LUMP, VERT_NORMALS_LUMP, VERT_NORMAL_INDICES_LUMP, DISP_LIGHTMAP_ALPHAS_LUMP, DISP_VERTS_LUMP, DISP_LIGHTMAP_SAMPLE_POS_LUMP, GAME_LUMP, LEAF_WATER_DATA_LUMP, PRIMITIVES_LUMP, PRIM_VERTS_LUMP, PRIM_INDICES_LUMP, PAK_FILE_LUMP, CLIP_PORTAL_VERTS_LUMP, CUBEMAPS_LUMP, TEXDATA_STRING_DATA_LUMP, TEXDATA_STRING_TABLE_LUMP, OVERLAYS_LUMP, LEAF_MIN_DIST_TO_WATER_LUMP, FACE_MACRO_TEXTURE_INFO_LUMP, DISP_TRIS_LUMP, PHYS_COLLIDE_SURFACE_LUMP, UNUSED_LUMP_50, UNUSED_LUMP_51, UNUSED_LUMP_52, LIGHTING_HDR_LUMP, WORLD_LIGHTS_HDR_LUMP, LEAF_LIGHT_HDR_1_LUMP, LEAF_LIGHT_HDR_2_LUMP, UNUSED_LUMP_57, UNUSED_LUMP_58, UNUSED_LUMP_59, UNUSED_LUMP_60, UNUSED_LUMP_61, UNUSED_LUMP_62, UNUSED_LUMP_63, MAX_LUMPS }; const char LUMP_DESCRIPTION[][64] = { "ENTITIES_LUMP", "PLANES_LUMP", "TEXDATA_LUMP", "VERTICES_LUMP", "VISIBILITY_LUMP", "NODES_LUMP", "TEXINFO_LUMP", "FACES_LUMP", "LIGHTING_LUMP", "OCCLUSION_LUMP", "LEAFS_LUMP", "UNUSED_LUMP_11", "EDGES_LUMP", "SURFEDGES_LUMP", "MODELS_LUMP", "WORLD_LIGHTS_LUMP", "LEAF_FACES_LUMP", "LEAF_BRUSHES_LUMP", "BRUSHES_LUMP", "BRUSH_SIDES_LUMP", "AREAS_LUMP", "AREA_PORTALS_LUMP", "PORTALS_LUMP", "CLUSTERS_LUMP", "PORTAL_VERTS_LUMP", "CLUSTER_PORTALS_LUMP", "DISPINFO_LUMP", "ORIGINAL_FACES_LUMP", "UNUSED_LUMP_28", "PHYS_COLLIDE_LUMP", "VERT_NORMALS_LUMP", "VERT_NORMAL_INDICES_LUMP", "DISP_LIGHTMAP_ALPHAS_LUMP", "DISP_VERTS_LUMP", "DISP_LIGHTMAP_SAMPLE_POS_LUMP", "GAME_LUMP", "LEAF_WATER_DATA_LUMP", "PRIMITIVES_LUMP", "PRIM_VERTS_LUMP", "PRIM_INDICES_LUMP", "PAK_FILE_LUMP", "CLIP_PORTAL_VERTS_LUMP", "CUBEMAPS_LUMP", "TEXDATA_STRING_DATA_LUMP", "TEXDATA_STRING_TABLE_LUMP", "OVERLAYS_LUMP", "LEAF_MIN_DIST_TO_WATER_LUMP", "FACE_MACRO_TEXTURE_INFO_LUMP", "DISP_TRIS_LUMP", "PHYS_COLLIDE_SURFACE_LUMP", "UNUSED_LUMP_50", "UNUSED_LUMP_51", "UNUSED_LUMP_52", "LIGHTING_HDR_LUMP", "WORLD_LIGHTS_HDR_LUMP", "LEAF_LIGHT_HDR_1_LUMP", "LEAF_LIGHT_HDR_2_LUMP", "UNUSED_LUMP_57", "UNUSED_LUMP_58", "UNUSED_LUMP_59", "UNUSED_LUMP_60", "UNUSED_LUMP_61", "UNUSED_LUMP_62", "UNUSED_LUMP_63" }; struct LumpEntry { int file_offset; int lump_length; int lump_version; char ident_code[4]; }; struct Header { int magic_number; int bsp_version; LumpEntry lump_table[MAX_LUMPS]; int map_revision; }; struct GameHeader { int num_lumps; // This is followed by this many GameLump entries (see below) }; struct GameLump { int lump_id; unsigned short lump_flags; unsigned short lump_version; int lump_offset; int lump_length; }; // This is the ID for the static prop game lump const int STATIC_PROP_ID = (('s'<<24)+('p'<<16)+('r'<<8)+'p'); struct StaticPropModelNames { int num_model_names; // This is followed by this many names, each 128 characters long }; struct StaticPropLeaves { int num_leaf_entries; // This is followed by this many unsigned shorts, indicating which BSP // leaves this prop occupies }; struct StaticProps { int num_static_props; // This is followed by this many StaticProp entries (see VBSPData.h), note // that there are two possible StaticProp versions, depending on the // version of the GameLump }; class VBSPReader { protected: std::string map_name; osg::ref_ptr bsp_data; osg::ref_ptr root_node; char * texdata_string; int * texdata_string_table; int num_texdata_string_table_entries; void processEntities(std::istream & str, int offset, int length); void processModels(std::istream & str, int offset, int length); void processPlanes(std::istream & str, int offset, int length); void processVertices(std::istream & str, int offset, int length); void processEdges(std::istream & str, int offset, int length); void processSurfEdges(std::istream & str, int offset, int length); void processFaces(std::istream & str, int offset, int length); void processTexInfo(std::istream & str, int offset, int length); void processTexData(std::istream & str, int offset, int length); void processTexDataStringTable(std::istream & str, int offset, int length); void processTexDataStringData(std::istream & str, int offset, int length); void processDispInfo(std::istream & str, int offset, int length); void processDispVerts(std::istream & str, int offset, int length); void processGameData(std::istream & str, int offset, int length); void processStaticProps(std::istream & str, int offset, int length, int lumpVersion); std::string getToken(std::string str, const char * delim, size_t & index); osg::ref_ptr createBlendShader(osg::Texture * tex1, osg::Texture * tex2); osg::ref_ptr readTextureFile(std::string file); osg::ref_ptr readMaterialFile(std::string file); void createScene(); public: VBSPReader(); virtual ~VBSPReader(); bool readFile(const std::string & file); osg::ref_ptr getRootNode(); }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/CMakeLists.txt0000644000175000017500000000055713151044751025336 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterBSP.cpp BITSET.cpp Q3BSPReader.cpp Q3BSPLoad.cpp VBSPData.cpp VBSPEntity.cpp VBSPGeometry.cpp VBSPReader.cpp ) SET(TARGET_H ReaderWriterBSP.h BITSET.h Q3BSPReader.h Q3BSPLoad.h VBSPData.h VBSPEntity.h VBSPGeometry.h VBSPReader.h ) #### end var setup ### SETUP_PLUGIN(bsp) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPGeometry.h0000644000175000017500000000257313151044751025235 0ustar albertoalberto #ifndef VBSP_GEOMETRY_H #define VBSP_GEOMETRY_H #include #include #include "VBSPData.h" namespace bsp { class VBSPGeometry { protected: VBSPData * bsp_data; osg::ref_ptr vertex_array; osg::ref_ptr normal_array; osg::ref_ptr texcoord_array; osg::ref_ptr primitive_set; osg::ref_ptr disp_vertex_array; osg::ref_ptr disp_normal_array; osg::ref_ptr disp_texcoord_array; osg::ref_ptr disp_vertex_attr_array; osg::ref_ptr disp_primitive_set; bool doesEdgeExist(int row, int col, int direction, int vertsPerEdge); osg::Vec3f getNormalFromEdges(int row, int col, unsigned char edgeBits, int firstVertex, int vertsPerEdge); void createDispSurface(Face & face, DisplaceInfo & dispInfo); public: VBSPGeometry(VBSPData * bspData); virtual ~VBSPGeometry(); void addFace(int faceIndex); osg::ref_ptr createGeometry(); }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/Q3BSPLoad.cpp0000644000175000017500000001576713151044751024743 0ustar albertoalberto #include "Q3BSPLoad.h" #include using namespace bsp; bool Q3BSPLoad::Load(const std::string& filename, int curveTessellation) { osgDB::ifstream file(filename.c_str(),std::ios::binary); if(!file.is_open()) { //errorLog.OutputError("Unable to open %s", filename); return false; } //read in header file.read((char*)&m_header, sizeof(BSP_HEADER)); //check header data is correct if( m_header.m_string[0]!='I' || m_header.m_string[1]!='B' || m_header.m_string[2]!='S' || m_header.m_string[3]!='P' || m_header.m_version !=0x2E ) { //errorLog.OutputError("%s is not a version 0x2E .bsp map file", filename); return false; } //Load in vertices LoadVertices(file); //Load in mesh indices //Calculate number of indices int numMeshIndices=m_header.m_directoryEntries[bspMeshIndices].m_length/sizeof(int); //Create space m_loadMeshIndices.resize(numMeshIndices); //read in the mesh indices file.seekg(m_header.m_directoryEntries[bspMeshIndices].m_offset,std::ios::beg); file.read((char*) &m_loadMeshIndices[0], m_header.m_directoryEntries[bspMeshIndices].m_length); //Load in faces LoadFaces(file, curveTessellation); //Load textures LoadTextures(file); //Load Lightmaps LoadLightmaps(file); //Load BSP Data LoadBSPData(file); //Load in entity string m_entityString.resize(m_header.m_directoryEntries[bspEntities].m_length); //Go to entity string in file file.seekg(m_header.m_directoryEntries[bspEntities].m_offset,std::ios::beg); file.read(&m_entityString[0], m_header.m_directoryEntries[bspEntities].m_length); //errorLog.OutputSuccess("%s Loaded successfully", filename); return true; } void Q3BSPLoad::LoadVertices(std::ifstream& aFile) { //calculate number of vertices int num_vertices=m_header.m_directoryEntries[bspVertices].m_length/sizeof(BSP_LOAD_VERTEX); //Create space for this many BSP_LOAD_VERTICES m_loadVertices.resize(num_vertices); //go to vertices in file aFile.seekg(m_header.m_directoryEntries[bspVertices].m_offset,std::ios::beg); //read in the vertices aFile.read((char*)&m_loadVertices[0], m_header.m_directoryEntries[bspVertices].m_length); } void Q3BSPLoad::LoadFaces(std::ifstream& aFile, int /*curveTessellation*/) { //calculate number of load faces int numTotalFaces=m_header.m_directoryEntries[bspFaces].m_length/sizeof(BSP_LOAD_FACE); //Create space for this many BSP_LOAD_FACES m_loadFaces.resize(numTotalFaces); //go to faces in file aFile.seekg(m_header.m_directoryEntries[bspFaces].m_offset,std::ios::beg); //read in the faces aFile.read((char*)&m_loadFaces[0], m_header.m_directoryEntries[bspFaces].m_length); } void Q3BSPLoad::LoadTextures(std::ifstream& aFile) { //Calculate number of textures int num_textures=m_header.m_directoryEntries[bspTextures].m_length/sizeof(BSP_LOAD_TEXTURE); //Create space for this many BSP_LOAD_TEXTUREs m_loadTextures.resize(num_textures); //Load textures aFile.seekg(m_header.m_directoryEntries[bspTextures].m_offset,std::ios::beg); aFile.read((char*)&m_loadTextures[0], m_header.m_directoryEntries[bspTextures].m_length); } void Q3BSPLoad::LoadLightmaps(std::ifstream& aFile) { //Calculate number of lightmaps int num_lightmaps=m_header.m_directoryEntries[bspLightmaps].m_length/sizeof(BSP_LOAD_LIGHTMAP); //Create space for this many BSP_LOAD_LIGHTMAPs m_loadLightmaps.resize(num_lightmaps); //Load textures aFile.seekg(m_header.m_directoryEntries[bspLightmaps].m_offset,std::ios::beg); aFile.read((char*)&m_loadLightmaps[0], m_header.m_directoryEntries[bspLightmaps].m_length); //Change the gamma settings on the lightmaps (make them brighter) float gamma=2.5f; for(int i=0; i 1.0f && (temp = (1.0f/r)) < scale) scale=temp; if(g > 1.0f && (temp = (1.0f/g)) < scale) scale=temp; if(b > 1.0f && (temp = (1.0f/b)) < scale) scale=temp; // scale up color values scale*=255.0f; r*=scale; g*=scale; b*=scale; //fill data back in m_loadLightmaps[i].m_lightmapData[j*3+0]=(unsigned char)r; m_loadLightmaps[i].m_lightmapData[j*3+1]=(unsigned char)g; m_loadLightmaps[i].m_lightmapData[j*3+2]=(unsigned char)b; //m_loadLightmaps[i].m_lightmapData[j*3+0]=(GLubyte)255; //m_loadLightmaps[i].m_lightmapData[j*3+1]=(GLubyte)255; //m_loadLightmaps[i].m_lightmapData[j*3+2]=(GLubyte)255; } } } void Q3BSPLoad::LoadBSPData(std::ifstream& aFile) { //Load leaves //Calculate number of leaves int numLeaves=m_header.m_directoryEntries[bspLeaves].m_length/sizeof(BSP_LOAD_LEAF); //Create space for this many BSP_LOAD_LEAFS m_loadLeaves.resize(numLeaves); //Load leaves aFile.seekg(m_header.m_directoryEntries[bspLeaves].m_offset,std::ios::beg); aFile.read((char*)&m_loadLeaves[0], m_header.m_directoryEntries[bspLeaves].m_length); //Load leaf faces array int num_leaf_faces=m_header.m_directoryEntries[bspLeafFaces].m_length/sizeof(int); //Create space for this many leaf faces m_loadLeafFaces.resize(num_leaf_faces); //Load leaf faces aFile.seekg(m_header.m_directoryEntries[bspLeafFaces].m_offset,std::ios::beg); aFile.read((char*)&m_loadLeafFaces[0], m_header.m_directoryEntries[bspLeafFaces].m_length); //Load Planes int num_planes=m_header.m_directoryEntries[bspPlanes].m_length/sizeof(BSP_LoadPlane); //Create space for this many planes m_loadPlanes.resize(num_planes); aFile.seekg(m_header.m_directoryEntries[bspPlanes].m_offset,std::ios::beg); aFile.read((char*)&m_loadPlanes[0], m_header.m_directoryEntries[bspPlanes].m_length); //Load nodes int num_nodes=m_header.m_directoryEntries[bspNodes].m_length/sizeof(BSP_NODE); //Create space for this many nodes m_loadNodes.resize(num_nodes); aFile.seekg(m_header.m_directoryEntries[bspNodes].m_offset,std::ios::beg); aFile.read((char*)&m_loadNodes[0], m_header.m_directoryEntries[bspNodes].m_length); //Load visibility data //load numClusters and bytesPerCluster aFile.seekg(m_header.m_directoryEntries[bspVisData].m_offset,std::ios::beg); aFile.read((char*)&m_loadVisibilityData, 2 * sizeof(int)); //Calculate the size of the bitset int bitsetSize=m_loadVisibilityData.m_numClusters*m_loadVisibilityData.m_bytesPerCluster; //Create space for bitset m_loadVisibilityData.m_bitset.resize(bitsetSize); //read bitset aFile.read((char*)&m_loadVisibilityData.m_bitset[0], bitsetSize); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPEntity.h0000644000175000017500000000324413151044751024712 0ustar albertoalberto #ifndef __VBSP_ENTITY_H_ #define __VBSP_ENTITY_H_ #include #include #include "VBSPData.h" namespace bsp { enum EntityClass { ENTITY_WORLDSPAWN, ENTITY_ENV, ENTITY_FUNC_BRUSH, ENTITY_PROP, ENTITY_INFO_DECAL, ENTITY_ITEM, ENTITY_OTHER }; class VBSPEntity { protected: VBSPData * bsp_data; EntityClass entity_class; std::string class_name; typedef std::pair EntityParameter; typedef std::map EntityParameters; EntityParameters entity_parameters; bool entity_visible; bool entity_transformed; int entity_model_index; std::string entity_model; osg::Vec3f entity_origin; osg::Vec3f entity_angles; osg::ref_ptr entity_geometry; void processWorldSpawn(); void processEnv(); void processFuncBrush(); void processProp(); void processInfoDecal(); void processItem(); osg::Vec3f getVector(std::string str); std::string getToken(std::string str, size_t & index); void parseParameters(std::string & entityText); osg::ref_ptr createBrushGeometry(); osg::ref_ptr createModelGeometry(); public: VBSPEntity(std::string & entityText, VBSPData * bspData); ~VBSPEntity(); EntityClass getClass(); bool isVisible(); osg::ref_ptr createGeometry(); }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSPData.h0000644000175000017500000001751113151044751024311 0ustar albertoalberto#ifndef __VBSP_DATA_H_ #define __VBSP_DATA_H_ #include #include #include #include namespace bsp { struct Plane { osg::Vec3f plane_normal; float origin_dist; int type; }; struct Edge { unsigned short vertex[2]; }; struct Face { unsigned short plane_index; unsigned char plane_side; unsigned char on_node; int first_edge; short num_edges; short texinfo_index; short dispinfo_index; short surface_fog_volume_id; unsigned char styles[4]; int light_offset; float face_area; int lightmap_texture_mins_in_luxels[2]; int lightmap_texture_size_in_luxels[2]; int original_face; unsigned short num_primitives; unsigned short first_primitive_id; unsigned int smoothing_groups; }; struct Model { osg::Vec3f bound_min; osg::Vec3f bound_max; osg::Vec3f model_origin; int head_node; int first_face; int num_faces; }; struct StaticPropV4 { osg::Vec3f prop_origin; osg::Vec3f prop_angles; unsigned short prop_type; unsigned short first_leaf; unsigned short leaf_count; unsigned char prop_solid; unsigned char prop_flags; unsigned int prop_skin; float min_fade_dist; float max_fade_dist; osg::Vec3f lighting_origin; }; struct StaticProp { osg::Vec3f prop_origin; osg::Vec3f prop_angles; unsigned short prop_type; unsigned short first_leaf; unsigned short leaf_count; unsigned char prop_solid; unsigned char prop_flags; unsigned int prop_skin; float min_fade_dist; float max_fade_dist; osg::Vec3f lighting_origin; float forced_fade_scale; }; struct TexInfo { float texture_vecs[2][4]; float lightmap_vecs[2][4]; int texture_flags; int texdata_index; }; struct TexData { osg::Vec3f texture_reflectivity; int name_string_table_id; int texture_width; int texture_height; int view_width; int view_height; }; struct DisplaceSubNeighbor { unsigned short neighbor_index; unsigned char neighbor_orient; unsigned char local_span; unsigned char neighbor_span; }; struct DisplaceNeighbor { DisplaceSubNeighbor sub_neighbors[2]; }; struct DisplaceCornerNeighbor { unsigned short neighbor_indices[4]; unsigned char neighbor_count; }; struct DisplaceInfo { osg::Vec3f start_position; int disp_vert_start; int disp_tri_start; int power; int min_tesselation; float smooth_angle; int surface_contents; unsigned short map_face; int lightmap_alpha_start; int lightmap_sample_pos_start; DisplaceNeighbor edge_neighbors[4]; DisplaceCornerNeighbor corner_neighbors[4]; unsigned int allowed_verts[10]; }; struct DisplacedVertex { osg::Vec3f displace_vec; float displace_dist; float alpha_blend; }; class VBSPData : public osg::Referenced { protected: typedef std::vector EntityList; EntityList entity_list; typedef std::vector ModelList; ModelList model_list; typedef std::vector PlaneList; PlaneList plane_list; typedef std::vector VertexList; VertexList vertex_list; typedef std::vector EdgeList; EdgeList edge_list; typedef std::vector SurfEdgeList; SurfEdgeList surface_edge_list; typedef std::vector FaceList; FaceList face_list; typedef std::vector TexInfoList; TexInfoList texinfo_list; typedef std::vector TexDataList; TexDataList texdata_list; typedef std::vector TexDataStringList; TexDataStringList texdata_string_list; typedef std::vector DisplaceInfoList; DisplaceInfoList dispinfo_list; typedef std::vector DisplacedVertexList; DisplacedVertexList displaced_vertex_list; typedef std::vector StaticPropModelList; StaticPropModelList static_prop_model_list; typedef std::vector StaticPropList; StaticPropList static_prop_list; typedef std::vector< osg::ref_ptr > StateSetList; StateSetList state_set_list; virtual ~VBSPData(); public: VBSPData(); void addEntity(std::string & newEntity); const int getNumEntities() const; const std::string & getEntity(int index) const; void addModel(Model & newModel); const int getNumModels() const; const Model & getModel(int index) const; void addPlane(Plane & newPlane); const int getNumPlanes() const; const Plane & getPlane(int index) const; void addVertex(osg::Vec3f & newVertex); const int getNumVertices() const; const osg::Vec3f & getVertex(int index) const; void addEdge(Edge & newEdge); const int getNumEdges() const; const Edge & getEdge(int index) const; void addSurfaceEdge(int & newSurfEdge); const int getNumSurfaceEdges() const; const int getSurfaceEdge(int index) const; void addFace(Face & newFace); const int getNumFaces() const; const Face & getFace(int index) const; void addTexInfo(TexInfo & newTexInfo); const int getNumTexInfos() const; const TexInfo & getTexInfo(int index) const; void addTexData(TexData & newTexData); const int getNumTexDatas() const; const TexData & getTexData(int index) const; void addTexDataString(std::string & newTexDataString); const int getNumTexDataStrings() const; const std::string & getTexDataString(int index) const; void addDispInfo(DisplaceInfo & newDispInfo); const int getNumDispInfos() const; const DisplaceInfo & getDispInfo(int index) const; void addDispVertex(DisplacedVertex & newDispVert); const int getNumDispVertices() const; const DisplacedVertex & getDispVertex(int index) const; void addStaticPropModel(std::string & newModel); const int getNumStaticPropModels() const; const std::string & getStaticPropModel(int index) const; void addStaticProp(StaticPropV4 & newProp); void addStaticProp(StaticProp & newProp); const int getNumStaticProps() const; const StaticProp & getStaticProp(int index) const; void addStateSet(osg::StateSet * stateSet); const int getNumStateSets() const; osg::StateSet * getStateSet(int index) const; }; } #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/VBSP_README.txt0000644000175000017500000001261113151044751025120 0ustar albertoalberto Source Engine BSP map reader for OSG by Jason Daly Overview -------- This plugin allows .bsp files from games that make use of Valve's Source engine (Half Life 2, etc) to be loaded by OSG. I've tested this plugin on several HL2 deathmatch maps, as well as some 3rd party maps. Using the Plugin ---------------- Unless you've got a 3rd party map that doesn't make use of any data from the original Source engine games, you'll need to extract the relevant maps and materials from the .gcf files that come with the game. A good tool for this is GCFScape, available at http://www.nemesis.thewavelength.net/index.php?p=26 The plugin expects the maps and materials to be arranged as they are in the .gcf file (maps in maps/ materials and textures in materials/). Only the maps/ and materials/ directories are used by this plugin. Models (in the models/ directory) are handled by the .mdl plugin, but the .bsp plugin typically will read model files as part of loading a .bsp map. It is important to preserve the file and directory structure as it is in the .gcf files, although you can merge the data from several files (different games) together. For example, you can extract the models/ directory from source models.gcf, the materials/ directory from source materials.gcf, and the maps/, models/, and materials/ directories from half-life 2 deathmatch.gcf and combine them together into a single parent directory (called "hl2data/", for example). This arrangement will let you load any of the HL2 deathmatch maps, with all of the props and materials that might be needed. If you're confused, here's a lame ASCII art drawing to confuse you even more: hl2data | +----maps | +----materials | +----models If you want to use the OSGFILEPATH environment variable to let OSG search for maps or models, point it to the parent directory ("hl2data" in the example above), then load your map like this: osgviewer maps/dm_runoff.bsp What Works ---------- All visible brush geometry and faces (except sky boxes). Displacement surfaces. Textures (including blended textures on displacement surfaces). This makes use of the VTF Reader plugin which was submitted at the same time as this plugin. Props (including static props embedded into the map file, and dynamic and physics props as loaded by the mdl plugin). Note that because of Source's physics engine, you might see some of the physics props suspended in the air when loading a map. The level designer placed them there so they fall to the ground when the level starts. Presumably, this is quicker and safer than trying to get them positioned exactly on the ground. What Doesn't Work (yet) ----------------------- Light maps. This requires reading the light map information lumps from the .bsp file, and creating a shader to render them on the various surfaces. Shouldn't be too hard. Currently, the plugin just treats lightmapped surfaces the same as vertex lit surfaces. Environment maps and shiny textures. Both of these require reading cube maps. Cube maps and environment mapping materials are typically stored inside the .bsp file as an embedded .pak file (essentially a .zip file with no compression. Reading them would require parsing the .pak file and reading the embedded .vmt to find the pointers to the base texture and cube map. Then the cube map must be read from the embedded .pak file as well. Finally, a shader would be created to render them. Currently, the plugin cheats by guessing the base texture from the embedded material name, and loading it. This seems to work well enough for now. Water. Water shaders in the Source engine are a lot more complicated than the generic lightmapped and vertex lit shaders. Currently, water surfaces just show up mostly white. At the very least, this needs environment map support to work properly. Sky boxes. These were left out by design (they tended to get in the way when doing the work required by the sponsor). These could easily be put back in, and this would probably make a good ReaderWriter option. World lights (light sources). Should be simple to read, but I don't know how many you'll find on a given map. If there are a lot of them, you'll have to be creative on how they're rendered. Environmental effects (fires, dust clouds, etc.). Each one would likely require specific code. Certain classes of props (collectable items, weapons, etc.) are not loaded right now. With these props, there is an explicit mapping between the prop's object class and the model that gets loaded for it. I just haven't set up these mappings yet. HDR materials, bump maps, detail props, and other eye-candy. Implement it if you want! :-) Acknowledgements ---------------- This plugin was written for some real-world work I'm doing at the University of Central Florida Institute for Simulation and Training. I want to thank our sponsors for funding our work and allowing me to contribute this code to the OSG community. This plugin wouldn't have been possible without Rof's "The Source Engine BSP Format" at http://www.geocities.com/cofrdrbob/bspformat.html which itself is based on Max McGuire's "Quake 2 BSP File Format" at http://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml Portions of the code borrow heavily from the Source SDK (especially the code for the displacement surfaces), so thanks to Valve for making much of that code public. Of course, this code would be superfluous without the Open Scene Graph and all of its contributors. OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bsp/BITSET.cpp0000644000175000017500000000233513151044751024270 0ustar albertoalberto////////////////////////////////////////////////////////////////////////////////////////// // BITSET.cpp // functions for class for set of bits to represent many true/falses // You may use this code however you wish, but if you do, please credit me and // provide a link to my website in a readme file or similar // Downloaded from: www.paulsprojects.net // Created: 8th August 2002 ////////////////////////////////////////////////////////////////////////////////////////// #include "memory.h" #include "BITSET.h" #include bool BITSET::Init(int numberOfBits) { //Delete any memory allocated to bits m_bits.clear(); //Calculate size m_numBytes=(numberOfBits>>3)+1; //Create memory m_bits.reserve(m_numBytes); m_bits_aux=&m_bits[0]; ClearAll(); return true; } void BITSET::ClearAll() { memset(m_bits_aux, 0, m_numBytes); } void BITSET::SetAll() { memset(m_bits_aux, 0xFF, m_numBytes); } void BITSET::Clear(int bitNumber) { m_bits_aux[bitNumber>>3] &= ~(1<<(bitNumber & 7)); } void BITSET::Set(int bitNumber) { m_bits_aux[bitNumber>>3] |= 1<<(bitNumber&7); } unsigned char BITSET::IsSet(int bitNumber) const { return static_cast(m_bits_aux[bitNumber>>3] & 1<<(bitNumber&7)); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/pic/0000755000175000017500000000000013151044751022556 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/pic/ReaderWriterPIC.cpp0000644000175000017500000001507413151044751026224 0ustar albertoalberto#include #include #include #include #include #include #include /**************************************************************************** * * Follows is code extracted from the simage library. Original Authors: * * Systems in Motion, * * * Peder Blekken * Morten Eriksen * Marius Bugge Monsen * * The original COPYING notice * * All files in this library are public domain, except simage_rgb.cpp which is * Copyright (c) Mark J Kilgard . I will contact Mark * very soon to hear if this source also can become public domain. * * Please send patches for bugs and new features to: . * * Peder Blekken * * * Ported into the OSG as a plugin, Robert Osfield December 2000. * Note, reference above to license of simage_rgb is not relevant to the OSG * as the OSG does not use it. Also for patches, bugs and new features * please send them direct to the OSG dev team rather than address above. * **********************************************************************/ #include #include #include #define ERROR_NO_ERROR 0 #define ERROR_READING_HEADER 1 #define ERROR_READING_PALETTE 2 #define ERROR_MEMORY 3 #define ERROR_READ_ERROR 4 static int picerror = ERROR_NO_ERROR; int simage_pic_error(char *buffer, int bufferlen) { switch (picerror) { case ERROR_READING_HEADER: strncpy(buffer, "PIC loader: Error reading header", bufferlen); break; case ERROR_READING_PALETTE: strncpy(buffer, "PIC loader: Error reading palette", bufferlen); break; case ERROR_MEMORY: strncpy(buffer, "PIC loader: Out of memory error", bufferlen); break; case ERROR_READ_ERROR: strncpy(buffer, "PIC loader: Read error", bufferlen); break; } return picerror; } /* byte order workaround *sigh* */ static int readint16(FILE *fp, int * res) { unsigned char tmp = 0; unsigned int tmp2; if (fread(&tmp, 1, 1, fp) != 1) return 0; *res = tmp; if (fread(&tmp, 1, 1, fp) != 1) return 0; tmp2 = tmp; tmp2 <<= 8; *res |= tmp2; return 1; } int simage_pic_identify(const char *, const unsigned char *header, int headerlen) { static unsigned char piccmp[] = {0x19, 0x91}; if (headerlen < 2) return 0; if (memcmp((const void*)header, (const void*)piccmp, 2) == 0) return 1; return 0; } unsigned char * simage_pic_load(const char *filename, int *width_ret, int *height_ret, int *numComponents_ret) { int w, h, width, height, i, j, format; unsigned char palette[256][3]; unsigned char * tmpbuf, * buffer, * ptr; FILE *fp = osgDB::fopen(filename, "rb"); if (!fp) return NULL; picerror = ERROR_NO_ERROR; fseek(fp, 2, SEEK_SET); if (!readint16(fp, &w)) { picerror = ERROR_READING_HEADER; fclose(fp); return NULL; } fseek(fp, 4, SEEK_SET); if (!readint16(fp, &h)) { picerror = ERROR_READING_HEADER; fclose(fp); return NULL; } width = w; height = h; if (width <= 0 || height <= 0) { fclose(fp); return NULL; } fseek(fp, 32, SEEK_SET); if (fread(&palette, 3, 256, fp) != 256) { picerror = ERROR_READING_PALETTE; } tmpbuf = new unsigned char [width]; buffer = new unsigned char [3*width*height]; if (tmpbuf == NULL || buffer == NULL) { picerror = ERROR_MEMORY; if (tmpbuf) delete [] tmpbuf; if (buffer) delete [] buffer; fclose(fp); return NULL; } ptr = buffer; for (i = 0; i < height; i++) { if (fread(tmpbuf, 1, width, fp) != (size_t) width) { picerror = ERROR_READ_ERROR; fclose(fp); if (tmpbuf) delete [] tmpbuf; if (buffer) delete [] buffer; buffer = NULL; width = height = 0; return NULL; } for (j = 0; j < width; j++) { int idx = tmpbuf[j]; *ptr++ = palette[idx][0]; *ptr++ = palette[idx][1]; *ptr++ = palette[idx][2]; } } format = 3; fclose(fp); *width_ret = width; *height_ret = height; *numComponents_ret = format; if (tmpbuf) delete [] tmpbuf; return buffer; } class ReaderWriterPIC : public osgDB::ReaderWriter { public: ReaderWriterPIC() { supportsExtension("pic","PIC Image format"); } virtual const char* className() const { return "PIC Image Reader"; } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(file, options); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; unsigned char *imageData = NULL; int width_ret; int height_ret; int numComponents_ret; imageData = simage_pic_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret); if (imageData==NULL) return ReadResult::FILE_NOT_HANDLED; int s = width_ret; int t = height_ret; int r = 1; int internalFormat = numComponents_ret; unsigned int pixelFormat = numComponents_ret == 1 ? GL_LUMINANCE : numComponents_ret == 2 ? GL_LUMINANCE_ALPHA : numComponents_ret == 3 ? GL_RGB : numComponents_ret == 4 ? GL_RGBA : (GLenum)-1; unsigned int dataType = GL_UNSIGNED_BYTE; osg::Image* pOsgImage = new osg::Image; pOsgImage->setFileName(fileName.c_str()); pOsgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); return pOsgImage; } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(pic, ReaderWriterPIC) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/pic/CMakeLists.txt0000644000175000017500000000011713151044751025315 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterPIC.cpp ) #### end var setup ### SETUP_PLUGIN(pic) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/imageio/0000755000175000017500000000000013151044751023415 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/imageio/ReaderWriterImageIO.cpp0000644000175000017500000013517713151044751027731 0ustar albertoalberto// Copyright Eric Wing // This plugin is the bridge to OS X's ImageIO framework // which provides access to all of Apple's supported image types. // This plugin plus the QTKit plugin obsoletes the old QuickTime plugin. // This requires 10.4+. (The old QuickTime plugin will not support 64-bit.) // Needs testing, especially in: // 8-bits per pixel (256 color vs GL_ALPHA, and what about GL_LUMINANCE)? // 16-bits per pixel (is GL_LUMINANCE_ALPHA a safe assumption?) // Non-power-of-two textures (especially odd sizes) // istream code path // ostream code path // write image, especially GL_LUMINANCE and GL_ALPHA paths and image formats other than PNG/JPEG // Enhancements needed: // Way to provide image type hint to ImageIO calls (via CFDictionary), // probably especially important for istream which lacks extension information. // Is there information we can use in the OSG options parameter? #import "TargetConditionals.h" #if (TARGET_OS_IPHONE) #import #import #import #import #import #else #include #endif // For the vImage framework (part of the Accerlate framework) #include // Used because CGDataProviderCreate became deprecated in 10.5 #include #include #include #include #include #include #include #include #include // for istream #include // for ios:: #ifndef GL_BGRA_EXT # define GL_BGRA_EXT GL_BGRA #endif /************************************************************** ***** Begin Callback functions for istream block reading ***** **************************************************************/ // This callback reads some bytes from an istream and copies it // to a Quartz buffer (supplied by Apple framework). size_t MyProviderGetBytesCallback(void* istream_userdata, void* quartz_buffer, size_t the_count) { std::istream* the_istream = (std::istream*)istream_userdata; the_istream->read((char*)quartz_buffer, the_count); return the_istream->gcount(); // return the actual number of bytes read } // This callback is triggered when the data provider is released // so you can clean up any resources. void MyProviderReleaseInfoCallback(void* istream_userdata) { // What should I put here? Do I need to close the istream? // The png and tga don't seem to. // std::istream* the_istream = (std::istream*)istream_userdata; } void MyProviderRewindCallback(void* istream_userdata) { std::istream* the_istream = (std::istream*)istream_userdata; the_istream->seekg(0, std::ios::beg); } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // CGDataProviderCreateSequential was introduced in 10.5; CGDataProviderCreate is deprecated off_t MyProviderSkipForwardBytesCallback(void* istream_userdata, off_t the_count) { std::istream* the_istream = (std::istream*)istream_userdata; off_t start_position = the_istream->tellg(); the_istream->seekg(the_count, std::ios::cur); off_t end_position = the_istream->tellg(); return (end_position - start_position); } #else // CGDataProviderCreate was deprecated in 10.5 void MyProviderSkipBytesCallback(void* istream_userdata, size_t the_count) { std::istream* the_istream = (std::istream*)istream_userdata; the_istream->seekg(the_count, std::ios::cur); } #endif /************************************************************** ***** End Callback functions for istream block reading ******** **************************************************************/ /************************************************************** ***** Begin Callback functions for ostream block writing ****** **************************************************************/ size_t MyConsumerPutBytesCallback(void* ostream_userdata, const void* quartz_buffer, size_t the_count) { std::ostream* the_ostream = (std::ostream*)ostream_userdata; the_ostream->write((char*)quartz_buffer, the_count); // Don't know how to get number of bytes actually written, so // just returning the_count. return the_count; } void MyConsumerReleaseInfoCallback(void* ostream_userdata) { std::ostream* the_ostream = (std::ostream*)ostream_userdata; the_ostream->flush(); } /************************************************************** ***** End Callback functions for ostream block writing ******** **************************************************************/ /************************************************************** ***** Begin Support functions for reading (stream and file) *** **************************************************************/ /* Create a CGImageSourceRef from raw data */ CGImageRef CreateCGImageFromDataStream(std::istream& fin) { CGImageRef image_ref = NULL; CGImageSourceRef source_ref; /* The easy way would be to use CGImageSourceCreateWithData, * but this presumes you have a known fixed-length buffer of data. * The istream makes this harder to know, so we use the ProviderCallbacks APIs CFDataRef the_cf_data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8*)the_data, CFIndex length, kCFAllocatorNull // do not free data buffer, must do it yourself ); source_ref = CGImageSourceCreateWithData(the_cf_data, NULL); */ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // CGDataProviderCreateSequential was introduced in 10.5; CGDataProviderCreate is deprecated CGDataProviderSequentialCallbacks provider_callbacks = { 0, MyProviderGetBytesCallback, MyProviderSkipForwardBytesCallback, MyProviderRewindCallback, MyProviderReleaseInfoCallback }; CGDataProviderRef data_provider = CGDataProviderCreateSequential(&fin, &provider_callbacks); #else // CGDataProviderCreate was deprecated in 10.5 CGDataProviderCallbacks provider_callbacks = { MyProviderGetBytesCallback, MyProviderSkipBytesCallback, MyProviderRewindCallback, MyProviderReleaseInfoCallback }; CGDataProviderRef data_provider = CGDataProviderCreate(&fin, &provider_callbacks); #endif // If we had a way of hinting at what the data type is, we could // pass this hint in the second parameter. source_ref = CGImageSourceCreateWithDataProvider(data_provider, NULL); CGDataProviderRelease(data_provider); if(!source_ref) { return NULL; } image_ref = CGImageSourceCreateImageAtIndex(source_ref, 0, NULL); /* Don't need the SourceRef any more (error or not) */ CFRelease(source_ref); return image_ref; } /* Create a CGImageSourceRef from a file. */ /* Remember to CFRelease the created image when done. */ CGImageRef CreateCGImageFromFile(const char* the_path) { CFURLRef the_url = NULL; CGImageRef image_ref = NULL; CGImageSourceRef source_ref = NULL; CFStringRef cf_string = NULL; /* Create a CFString from a C string */ cf_string = CFStringCreateWithCString( NULL, the_path, kCFStringEncodingUTF8 ); if(!cf_string) { OSG_WARN << "CreateCGImageFromFile :: could not create CCFSTring" << std::endl; return NULL; } /* Create a CFURL from a CFString */ the_url = CFURLCreateWithFileSystemPath( NULL, cf_string, kCFURLPOSIXPathStyle, false ); /* Don't need the CFString any more (error or not) */ CFRelease(cf_string); if(!the_url) { OSG_WARN << "CreateCGImageFromFile :: could not create CFUrl" << std::endl; return NULL; } source_ref = CGImageSourceCreateWithURL(the_url, NULL); /* Don't need the URL any more (error or not) */ CFRelease(the_url); if(!source_ref) { OSG_WARN << "CreateCGImageFromFile :: could not create ImageSource" << std::endl; return NULL; } // Get the first item in the image source (some image formats may // contain multiple items). image_ref = CGImageSourceCreateImageAtIndex(source_ref, 0, NULL); if (!image_ref) { OSG_WARN << "CreateCGImageFromFile :: could not get Image" << std::endl; } /* Don't need the SourceRef any more (error or not) */ CFRelease(source_ref); return image_ref; } namespace { template void consume4(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data) { T* dst_data_ptr = dst_data; for (int y = height - 1; y >= 0; y--) // flip y { T* src_data_ptr = src_data + y*src_stride; for (int x = 0; x < width; x++) { #if OSG_GLES2_FEATURES *dst_data_ptr++ = *src_data_ptr++; // red *dst_data_ptr++ = *src_data_ptr++; // green *dst_data_ptr++ = *src_data_ptr++; // blue #else unsigned char r = *src_data_ptr++; unsigned char g = *src_data_ptr++; unsigned char b = *src_data_ptr++; *dst_data_ptr++ = b; // blue *dst_data_ptr++ = g; // green *dst_data_ptr++ = r; // red #endif *dst_data_ptr++ = *src_data_ptr++; // alpha } } } template void consume3(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data) { T* dst_data_ptr = dst_data; for (int y = height - 1; y >= 0; y--) // flip y { T* src_data_ptr = src_data + y*src_stride; for (int x = 0; x < width; x++) { #if OSG_GLES2_FEATURES *dst_data_ptr++ = *src_data_ptr++; // red *dst_data_ptr++ = *src_data_ptr++; // green *dst_data_ptr++ = *src_data_ptr++; // blue #else unsigned char r = *src_data_ptr++; unsigned char g = *src_data_ptr++; unsigned char b = *src_data_ptr++; *dst_data_ptr++ = b; // blue *dst_data_ptr++ = g; // green *dst_data_ptr++ = r; // red #endif } } } template void consume2(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data) { T* dst_data_ptr = dst_data; for (int y = height - 1; y >= 0; y--) // flip y { T* src_data_ptr = src_data + y*src_stride; for (int x = 0; x < width; x++) { *dst_data_ptr++ = *src_data_ptr++; // red (luminance) *dst_data_ptr++ = *src_data_ptr++; // green (alpha) } } } template void consume1(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data) { T* dst_data_ptr = dst_data; for (int y = height - 1; y >= 0; y--) // flip y { T* src_data_ptr = src_data + y*src_stride; for (int x = 0; x < width; x++) *dst_data_ptr++ = *src_data_ptr++; // red } } template bool consume(size_t channels, size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data) { if (channels == 4) { consume4(width, height, src_data, src_stride, dst_data); return true; } else if (channels == 3) { consume3(width, height, src_data, src_stride, dst_data); return true; } else if (channels == 2) { consume2(width, height, src_data, src_stride, dst_data); return true; } else if (channels == 1) { consume1(width, height, src_data, src_stride, dst_data); return true; } return false; } }// anonymous namespace /* Once we have our image (CGImageRef), we need to get it into an osg::Image */ // TODO: GL3 core profile osg::Image* CreateOSGImageFromCGImage(CGImageRef image_ref) { size_t src_width = CGImageGetWidth(image_ref); size_t src_height = CGImageGetHeight(image_ref); size_t src_bits_per_pixel = CGImageGetBitsPerPixel(image_ref); size_t src_bytes_per_row = CGImageGetBytesPerRow(image_ref); size_t src_bits_per_component = CGImageGetBitsPerComponent(image_ref); CGImageAlphaInfo src_alpha_info = CGImageGetAlphaInfo(image_ref); // CGBitmapInfo src_bitmap_info = CGImageGetBitmapInfo(image_ref); CFDataRef rawData = CGDataProviderCopyData(CGImageGetDataProvider(image_ref)); const UInt8* src_data = CFDataGetBytePtr(rawData); size_t channels = src_bits_per_pixel/src_bits_per_component; uint8_t* image_data = new uint8_t[int(src_width*src_height*channels*(src_bits_per_component/8.0))]; size_t stride = src_bytes_per_row*(8.0/src_bits_per_component); // Suppose 4 channels GLenum type = GL_UNSIGNED_BYTE; GLint internal_format = GL_RGBA; GLenum pixel_format = GL_BGRA; // Should be faster than RGBA on x86 if (channels == 3) { internal_format = GL_RGB; pixel_format = GL_BGR; } else if (channels == 2) { #if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE) internal_format = GL_RG; // GL_RG8 pixel_format = GL_RG; #else internal_format = GL_LUMINANCE_ALPHA; pixel_format = GL_LUMINANCE_ALPHA; #endif } else if (channels == 1) { #if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE) internal_format = GL_RED; // GL_R8 pixel_format = GL_RED; #else if (src_alpha_info == kCGImageAlphaOnly) { internal_format = GL_ALPHA; pixel_format = GL_ALPHA; } else { internal_format = GL_LUMINANCE; pixel_format = GL_LUMINANCE; } #endif } #if OSG_GLES2_FEATURES pixel_format = internal_format; // Needed by spec #endif bool readSuccess = false; if (src_bits_per_component == 8) { uint8_t* src_data_cast = (uint8_t*)(src_data); uint8_t* dst_data = image_data; readSuccess = consume(channels, src_width, src_height, src_data_cast, stride, dst_data); } else if (src_bits_per_component == 16) { type = GL_UNSIGNED_SHORT; uint16_t* src_data_cast = (uint16_t*)(src_data); uint16_t* dst_data = (uint16_t*)image_data; readSuccess = consume(channels, src_width, src_height, src_data_cast, stride, dst_data); } else if (src_bits_per_component == 32) { type = GL_FLOAT; float* src_data_cast = (float*)(src_data); float* dst_data = (float*)image_data; readSuccess = consume(channels, src_width, src_height, src_data_cast, stride, dst_data); } CFRelease(rawData); if (!readSuccess) { OSG_WARN << "Can't load image (via imageio plugin): Unsupported number of channels"; delete[] image_data; return NULL; } osg::Image* osg_image = new osg::Image; osg_image->setImage(src_width, src_height, 1, internal_format, pixel_format, type, image_data, osg::Image::USE_NEW_DELETE); return osg_image; } /************************************************************** ***** End Support functions for reading (stream and file) ***** **************************************************************/ /************************************************************** ***** Begin Support functions for writing (stream and file)**** **************************************************************/ /* Create a CGImageRef from osg::Image. * Code adapted from * http://developer.apple.com/samplecode/OpenGLScreenSnapshot/listing2.html */ CGImageRef CreateCGImageFromOSGData(const osg::Image& osg_image) { size_t image_width = osg_image.s(); size_t image_height = osg_image.t(); /* From Apple's header for CGBitmapContextCreate() * Each row of the bitmap consists of `bytesPerRow' bytes, which must be at * least `(width * bitsPerComponent * number of components + 7)/8' bytes. */ size_t target_bytes_per_row; CGColorSpaceRef color_space; CGBitmapInfo bitmap_info; /* From what I can figure out so far... * We need to create a CGContext connected to the data we want to save * and then call CGBitmapContextCreateImage() on that context to get * a CGImageRef. * However, OS X only allows 4-component image formats (e.g. RGBA) and not * just RGB for the RGB-based CGContext. So for a 24-bit image coming in, * we need to expand the data to 32-bit. * The easiest and fastest way to do that is through the vImage framework * which is part of the Accelerate framework. * Also, the osg::Image data coming in is inverted from what we want, so * we need to invert the image too. Since the osg::Image is const, * we don't want to touch the data, so again we turn to the vImage framework * and invert the data. */ vImage_Buffer vimage_buffer_in = { (void*)osg_image.data(), // need to override const, but we don't modify the data so it's safe image_height, image_width, osg_image.getRowSizeInBytes() }; void* out_image_data; vImage_Buffer vimage_buffer_out = { NULL, // will fill-in in switch image_height, image_width, 0 // will fill-in in switch }; vImage_Error vimage_error_flag; // FIXME: Do I want to use format, type, or internalFormat? switch(osg_image.getPixelFormat()) { case GL_LUMINANCE: { bitmap_info = kCGImageAlphaNone; target_bytes_per_row = (image_width * 8 + 7)/8; //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); color_space = CGColorSpaceCreateDeviceGray(); if(NULL == color_space) { return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Now invert the image vimage_error_flag = vImageVerticalReflect_Planar8( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData for GL_LUMINANCE, vImageVerticalReflect_Planar8 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } case GL_ALPHA: { bitmap_info = kCGImageAlphaOnly; target_bytes_per_row = (image_width * 8 + 7)/8; // According to: // http://developer.apple.com/qa/qa2001/qa1037.html // colorSpace=NULL is for alpha only color_space = NULL; // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Now invert the image vimage_error_flag = vImageVerticalReflect_Planar8( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData for GL_ALPHA, vImageVerticalReflect_Planar8 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); return NULL; } break; } /* case GL_LUMINANCE_ALPHA: { // I don't know if we can support this. // The qa1037 doesn't show both gray+alpha. break; } */ case GL_RGB: { bitmap_info = kCGImageAlphaNoneSkipFirst; target_bytes_per_row = (image_width * 8 * 4 + 7)/8; //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); if(NULL == color_space) { OSG_WARN << "In CreateCGImageFromOSGData, CGColorSpaceCreateWithName failed" << std::endl; return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } // Use vImage to get an RGB buffer into ARGB. vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; vimage_error_flag = vImageConvert_RGB888toARGB8888( &vimage_buffer_in, NULL, // we don't have a buffer containing alpha values 255, // The alpha value we want given to all pixels since we don't have a buffer &vimage_buffer_out, 0, // premultiply? kvImageNoFlags // Only responds to kvImageDoNotTile, but I think we want tiling/threading ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageConvert_RGB888toARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } // Now invert the image vimage_error_flag = vImageVerticalReflect_ARGB8888( &vimage_buffer_out, &vimage_buffer_out, // reuse the same buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageAffineWarp_ARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } case GL_RGBA: { bitmap_info = kCGImageAlphaPremultipliedLast; target_bytes_per_row = osg_image.getRowSizeInBytes(); //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); if(NULL == color_space) { OSG_WARN << "In CreateCGImageFromOSGData, CGColorSpaceCreateWithName failed" << std::endl; return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Invert the image vimage_error_flag = vImageVerticalReflect_ARGB8888( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageAffineWarp_ARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } case GL_BGRA: { if(GL_UNSIGNED_INT_8_8_8_8_REV == osg_image.getDataType()) { #if __BIG_ENDIAN__ bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */ #else bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ #endif } else { // FIXME: Don't know how to handle this case bitmap_info = kCGImageAlphaPremultipliedLast; } target_bytes_per_row = osg_image.getRowSizeInBytes(); //color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); if(NULL == color_space) { OSG_WARN << "In CreateCGImageFromOSGData, CGColorSpaceCreateWithName failed" << std::endl; return NULL; } // out_image_data = calloc(target_bytes_per_row, image_height); out_image_data = malloc(target_bytes_per_row * image_height); if(NULL == out_image_data) { OSG_WARN << "In CreateCGImageFromOSGData, malloc failed" << std::endl; CGColorSpaceRelease(color_space); return NULL; } vimage_buffer_out.data = out_image_data; vimage_buffer_out.rowBytes = target_bytes_per_row; // Invert the image vimage_error_flag = vImageVerticalReflect_ARGB8888( &vimage_buffer_in, // since the osg_image is const... &vimage_buffer_out, // don't reuse the buffer kvImageNoFlags ); if(vimage_error_flag != kvImageNoError) { OSG_WARN << "In CreateCGImageFromOSGData, vImageAffineWarp_ARGB8888 failed with vImage Error Code: " << vimage_error_flag << std::endl; free(out_image_data); CGColorSpaceRelease(color_space); return NULL; } break; } // FIXME: Handle other cases. // Use vImagePermuteChannels_ARGB8888 to swizzle bytes default: { OSG_WARN << "In CreateCGImageFromOSGData: Sorry support for this format is not implemented." << std::endl; return NULL; break; } } CGContextRef bitmap_context = CGBitmapContextCreate( vimage_buffer_out.data, vimage_buffer_out.width, vimage_buffer_out.height, 8, vimage_buffer_out.rowBytes, color_space, bitmap_info ); /* Done with color space */ CGColorSpaceRelease(color_space); if(NULL == bitmap_context) { free(out_image_data); return NULL; } /* Make an image out of our bitmap; does a cheap vm_copy of the bitmap */ CGImageRef image_ref = CGBitmapContextCreateImage(bitmap_context); /* Done with data */ free(out_image_data); /* Done with bitmap_context */ CGContextRelease(bitmap_context); return image_ref; } /* Create a CGImageDestinationRef from a file. */ /* Remember to CFRelease when done. */ CGImageDestinationRef CreateCGImageDestinationFromFile(const char* the_path, const osgDB::ReaderWriter::Options* the_options) { CFURLRef the_url = NULL; CFStringRef cf_string = NULL; CFStringRef uti_type = NULL; CGImageDestinationRef dest_ref = NULL; bool found_png_option = false; bool found_jpeg_option = false; float compression_quality = 1.0f; /* Create a CFString from a C string */ cf_string = CFStringCreateWithCString( NULL, the_path, kCFStringEncodingUTF8 ); if(!cf_string) { return NULL; } /* Create a CFURL from a CFString */ the_url = CFURLCreateWithFileSystemPath( NULL, cf_string, kCFURLPOSIXPathStyle, false ); /* Don't need the CFString any more (error or not) */ CFRelease(cf_string); if(!the_url) { return NULL; } if(the_options) { std::istringstream iss(the_options->getOptionString()); std::string opt; while (iss >> opt) { // Not handled: The user could do something stupid and specify both PNG and JPEG options. if(opt=="PNG_COMPRESSION") { found_png_option = true; // I don't see an option to set PNG compression levels in the API so this info is unused. int level; iss >> level; } else if(opt=="JPEG_QUALITY") { found_jpeg_option = true; // Chances are that people are specifying values in libjpeg ranges and not ImageIO ranges. // ImageIO is normalized between 0.0 to 1.0 where 1.0 is lossless and 0 is max compression. // I am uncertain what libjpeg's range is. I'm guessing 0-100. int quality; iss >> quality; compression_quality = (float)quality/100.0f; } } } CFStringRef path_extension = CFURLCopyPathExtension(the_url); if(NULL == path_extension) { if(found_jpeg_option) { uti_type = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, CFSTR("jpg"), kUTTypeImage // "public.image" ); } else { uti_type = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, CFSTR("png"), kUTTypeImage // "public.image" ); } } else { uti_type = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, path_extension, kUTTypeImage // "public.image" ); CFRelease(path_extension); } dest_ref = CGImageDestinationCreateWithURL( the_url, uti_type, 1, // image file will contain only one image NULL ); CFRelease(uti_type); CFRelease(the_url); // Not handled: The user could do something stupid and specify both PNG and JPEG options. if(found_jpeg_option) { // Do a bunch of work to setup a CFDictionary containing the jpeg compression properties. CFStringRef the_keys[1]; CFNumberRef the_values[1]; CFDictionaryRef the_dict; the_keys[0] = kCGImageDestinationLossyCompressionQuality; the_values[0] = CFNumberCreate( NULL, kCFNumberFloat32Type, &compression_quality ); the_dict = CFDictionaryCreate(NULL, (const void**)&the_keys, (const void**)&the_values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(the_values[0]); // Now that we have the dict, actually set the property. CGImageDestinationSetProperties(dest_ref, the_dict); CFRelease(the_dict); } return dest_ref; } /* Create a CGImageDestinationRef from a file. */ /* Remember to CFRelease when done. */ CGImageDestinationRef CreateCGImageDestinationFromDataStream(std::ostream& fout, const osgDB::ReaderWriter::Options* the_options) { CFStringRef uti_type = NULL; CGImageDestinationRef dest_ref = NULL; bool found_png_option = false; bool found_jpeg_option = false; float compression_quality = 1.0f; CGDataConsumerCallbacks consumer_callbacks = { MyConsumerPutBytesCallback, MyConsumerReleaseInfoCallback }; CGDataConsumerRef data_consumer = CGDataConsumerCreate(&fout, &consumer_callbacks); if(the_options) { std::istringstream iss(the_options->getOptionString()); std::string opt; while (iss >> opt) { // Not handled: The user could do something stupid and specify both PNG and JPEG options. if(opt=="PNG_COMPRESSION") { found_png_option = true; // I don't see an option to set PNG compression levels in the API so this info is unused. int level; iss >> level; } else if(opt=="JPEG_QUALITY") { found_jpeg_option = true; // Chances are that people are specifying values in libjpeg ranges and not ImageIO ranges. // ImageIO is normalized between 0.0 to 1.0 where 1.0 is lossless and 0 is max compression. // I am uncertain what libjpeg's range is. I'm guessing 0-100. int quality; iss >> quality; compression_quality = (float)quality/100.0f; } } } if(found_jpeg_option) { uti_type = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, CFSTR("jpg"), kUTTypeImage // "public.image" ); } else // default to png { uti_type = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, CFSTR("png"), kUTTypeImage // "public.image" ); } // If we had a way of hinting at what the data type is, we could // pass this hint in the second parameter. dest_ref = CGImageDestinationCreateWithDataConsumer( data_consumer, uti_type, 1, // image file will contain only one image NULL ); CGDataConsumerRelease(data_consumer); CFRelease(uti_type); // Not handled: The user could do something stupid and specify both PNG and JPEG options. if(found_jpeg_option) { // Do a bunch of work to setup a CFDictionary containing the jpeg compression properties. CFStringRef the_keys[1]; CFNumberRef the_values[1]; CFDictionaryRef the_dict; the_keys[0] = kCGImageDestinationLossyCompressionQuality; the_values[0] = CFNumberCreate( NULL, kCFNumberFloat32Type, &compression_quality ); the_dict = CFDictionaryCreate(NULL, (const void**)&the_keys, (const void**)&the_values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(the_values[0]); // Now that we have the dict, actually set the property. CGImageDestinationSetProperties(dest_ref, the_dict); CFRelease(the_dict); } return dest_ref; } /************************************************************** ***** End Support functions for writing (stream and file) ***** **************************************************************/ class ReaderWriterImageIO : public osgDB::ReaderWriter { public: ReaderWriterImageIO() { supportsExtension("jpg", "jpg image file"); supportsExtension("jpeg", "jpeg image file"); supportsExtension("jpe", "jpe image file"); supportsExtension("jp2", "jp2 image file"); supportsExtension("tiff", "tiff image file"); supportsExtension("tif", "tif image file"); supportsExtension("gif", "gif image file"); supportsExtension("png", "png image file"); supportsExtension("pict", "pict image file"); supportsExtension("pct", "pct image file"); supportsExtension("pic", "pic image file"); supportsExtension("bmp", "bmp image file"); supportsExtension("BMPf", "BMPf image file"); supportsExtension("ico", "ico image file"); supportsExtension("icns", "icns image file"); supportsExtension("tga", "tga image file"); supportsExtension("targa", "targa image file"); supportsExtension("psd", "psd image file"); supportsExtension("pdf", "pdf image file"); supportsExtension("eps", "eps image file"); supportsExtension("epi", "epi image file"); supportsExtension("epsf", "epsf image file"); supportsExtension("epsi", "epsi image file"); supportsExtension("ps", "postscript image file"); supportsExtension("dng", "dng image file"); supportsExtension("cr2", "cr2 image file"); supportsExtension("crw", "crw image file"); supportsExtension("fpx", "fpx image file"); supportsExtension("fpxi", "fpxi image file"); supportsExtension("raf", "raf image file"); supportsExtension("dcr", "dcr image file"); supportsExtension("ptng", "ptng image file"); supportsExtension("pnt", "pnt image file"); supportsExtension("mac", "mac image file"); supportsExtension("mrw", "mrw image file"); supportsExtension("nef", "nef image file"); supportsExtension("orf", "orf image file"); supportsExtension("exr", "exr image file"); supportsExtension("qti", "qti image file"); supportsExtension("qtif", "qtif image file"); supportsExtension("hdr", "hdr image file"); supportsExtension("sgi", "sgi image file"); supportsExtension("srf", "srf image file"); supportsExtension("cur", "cur image file"); supportsExtension("xbm", "xbm image file"); supportsExtension("raw", "raw image file"); } virtual const char* className() const { return "Mac OS X ImageIO based Image Reader/Writer"; } virtual bool acceptsExtension(const std::string& extension) const { // ImageIO speaks in UTIs. // http://developer.apple.com/graphicsimaging/workingwithimageio.html // The Cocoa drawing guide lists these and says to use the // imageFileTypes class method of NSImage to get a complete // list of extensions. But remember ImageIO may support more formats // than Cocoa. // http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Images/chapter_7_section_3.html // Apple's UTI guide: // http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/utilist/chapter_4_section_1.html return osgDB::equalCaseInsensitive(extension,"jpg") || osgDB::equalCaseInsensitive(extension,"jpeg") || osgDB::equalCaseInsensitive(extension,"jpe") || osgDB::equalCaseInsensitive(extension,"jp2") || osgDB::equalCaseInsensitive(extension,"tiff") || osgDB::equalCaseInsensitive(extension,"tif") || osgDB::equalCaseInsensitive(extension,"gif") || osgDB::equalCaseInsensitive(extension,"png") || osgDB::equalCaseInsensitive(extension,"pict") || osgDB::equalCaseInsensitive(extension,"pct") || osgDB::equalCaseInsensitive(extension,"pic") || osgDB::equalCaseInsensitive(extension,"bmp") || osgDB::equalCaseInsensitive(extension,"BMPf") || osgDB::equalCaseInsensitive(extension,"ico") || osgDB::equalCaseInsensitive(extension,"icns") || osgDB::equalCaseInsensitive(extension,"tga") || osgDB::equalCaseInsensitive(extension,"targa") || osgDB::equalCaseInsensitive(extension,"psd") || osgDB::equalCaseInsensitive(extension,"pdf") || osgDB::equalCaseInsensitive(extension,"eps") || osgDB::equalCaseInsensitive(extension,"epi") || osgDB::equalCaseInsensitive(extension,"epsf") || osgDB::equalCaseInsensitive(extension,"epsi") || osgDB::equalCaseInsensitive(extension,"ps") || osgDB::equalCaseInsensitive(extension,"dng") || osgDB::equalCaseInsensitive(extension,"cr2") || osgDB::equalCaseInsensitive(extension,"crw") || osgDB::equalCaseInsensitive(extension,"fpx") || osgDB::equalCaseInsensitive(extension,"fpxi") || osgDB::equalCaseInsensitive(extension,"raf") || osgDB::equalCaseInsensitive(extension,"dcr") || osgDB::equalCaseInsensitive(extension,"ptng") || osgDB::equalCaseInsensitive(extension,"pnt") || osgDB::equalCaseInsensitive(extension,"mac") || osgDB::equalCaseInsensitive(extension,"mrw") || osgDB::equalCaseInsensitive(extension,"nef") || osgDB::equalCaseInsensitive(extension,"orf") || osgDB::equalCaseInsensitive(extension,"exr") || osgDB::equalCaseInsensitive(extension,"qti") || osgDB::equalCaseInsensitive(extension,"qtif") || osgDB::equalCaseInsensitive(extension,"hdr") || osgDB::equalCaseInsensitive(extension,"sgi") || osgDB::equalCaseInsensitive(extension,"srf") || osgDB::equalCaseInsensitive(extension,"cur") || osgDB::equalCaseInsensitive(extension,"xbm") || osgDB::equalCaseInsensitive(extension,"raw"); } ReadResult readImageStream(std::istream& fin) const { // Call ImageIO to load the image. CGImageRef cg_image_ref = CreateCGImageFromDataStream(fin); if (NULL == cg_image_ref) return ReadResult::FILE_NOT_FOUND; // Create an osg::Image from the CGImageRef. osg::Image* osg_image = CreateOSGImageFromCGImage(cg_image_ref); CFRelease(cg_image_ref); return osg_image; } virtual ReadResult readImage(std::istream& fin, const osgDB::ReaderWriter::Options* the_options = NULL) const { ReadResult read_result = readImageStream(fin); return read_result; } ReadResult readImageFile(const std::string& file_name) const { OSG_INFO << "imageio readImageFile: " << file_name << std::endl; // Call ImageIO to load the image. CGImageRef cg_image_ref = CreateCGImageFromFile(file_name.c_str()); if (NULL == cg_image_ref) return ReadResult::FILE_NOT_FOUND; // Create an osg::Image from the CGImageRef. osg::Image* osg_image = CreateOSGImageFromCGImage(cg_image_ref); CFRelease(cg_image_ref); if (!osg_image) return ReadResult::INSUFFICIENT_MEMORY_TO_LOAD; return osg_image; } virtual ReadResult readImage(const std::string& file_name, const osgDB::ReaderWriter::Options* the_options) const { std::string ext = osgDB::getLowerCaseFileExtension(file_name); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string full_file_name = osgDB::findDataFile( file_name, the_options ); if (full_file_name.empty()) return ReadResult::FILE_NOT_FOUND; #if 1 ReadResult read_result = readImageFile(full_file_name); #else // Only here to help test istream backend. The file version is better because // the filenname.extension could potentially be used by ImageIO to hint what the format type is. osgDB::ifstream istream(full_file_name.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::FILE_NOT_HANDLED; ReadResult read_result = readImage(istream); #endif if(read_result.validImage()) { read_result.getImage()->setFileName(full_file_name); } return read_result; } WriteResult writeImageStream(const osg::Image& osg_image, std::ostream& fout, const osgDB::ReaderWriter::Options* the_options) const { if (!osg_image.isDataContiguous()) { return WriteResult::FILE_NOT_HANDLED; } WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; CGImageDestinationRef cg_dest_ref = CreateCGImageDestinationFromDataStream(fout, the_options); if (NULL == cg_dest_ref) return WriteResult::ERROR_IN_WRITING_FILE; CGImageRef cg_image_ref = CreateCGImageFromOSGData(osg_image); if(NULL == cg_image_ref) { CFRelease(cg_dest_ref); return WriteResult::ERROR_IN_WRITING_FILE; } CGImageDestinationAddImage(cg_dest_ref, cg_image_ref, NULL); if(CGImageDestinationFinalize(cg_dest_ref)) { ret_val = WriteResult::FILE_SAVED; } else { ret_val = WriteResult::ERROR_IN_WRITING_FILE; } CFRelease(cg_image_ref); CFRelease(cg_dest_ref); return WriteResult::FILE_SAVED; } virtual WriteResult writeImage(const osg::Image& osg_image, std::ostream& fout, const osgDB::ReaderWriter::Options* the_options) const { WriteResult write_result = writeImageStream(osg_image, fout, the_options); return write_result; } WriteResult writeImageFile(const osg::Image& osg_image, const std::string& full_file_name, const osgDB::ReaderWriter::Options* the_options) const { if (!osg_image.isDataContiguous()) { return WriteResult::FILE_NOT_HANDLED; } WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; // Call ImageIO to load the image. CGImageDestinationRef cg_dest_ref = CreateCGImageDestinationFromFile(full_file_name.c_str(), the_options); if (NULL == cg_dest_ref) return WriteResult::ERROR_IN_WRITING_FILE; CGImageRef cg_image_ref = CreateCGImageFromOSGData(osg_image); if(NULL == cg_image_ref) { CFRelease(cg_dest_ref); return WriteResult::ERROR_IN_WRITING_FILE; } CGImageDestinationAddImage(cg_dest_ref, cg_image_ref, NULL); if(CGImageDestinationFinalize(cg_dest_ref)) { ret_val = WriteResult::FILE_SAVED; } else { ret_val = WriteResult::ERROR_IN_WRITING_FILE; } CFRelease(cg_image_ref); CFRelease(cg_dest_ref); return WriteResult::FILE_SAVED; } virtual WriteResult writeImage(const osg::Image& osg_image, const std::string& file_name, const osgDB::ReaderWriter::Options* the_options) const { std::string ext = osgDB::getFileExtension(file_name); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; if (!osg_image.isDataContiguous()) { return WriteResult::FILE_NOT_HANDLED; } WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; #if 1 // FIXME: Something may need to provide a proper writable location for the files. std::string full_file_name; full_file_name = file_name; return writeImageFile(osg_image, full_file_name, the_options); #else // Only here to help test ostream backend. The file version is better because // the filenname.extension could potentially be used by ImageIO to hint what the format type is. osgDB::ofstream fout(file_name.c_str(), std::ios::out | std::ios::binary); if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; return writeImage(osg_image, fout, the_options); #endif } virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(fin, options); } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(file, options); } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(imageio, ReaderWriterImageIO) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/imageio/CMakeLists.txt0000644000175000017500000000077513151044751026166 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterImageIO.cpp ) IF (APPLE) IF(OSG_BUILD_PLATFORM_IPHONE OR OSG_BUILD_PLATFORM_IPHONE_SIMULATOR) # compile FileUtils.cpp as objective-c++ SET_SOURCE_FILES_PROPERTIES(ReaderWriterImageIO.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++" ) ENDIF() ENDIF() SET(TARGET_ADDED_LIBRARIES) SET(TARGET_LIBRARIES_VARS IMAGEIO_LIBRARY ) SET(TARGET_EXTERNAL_LIBRARIES "/System/Library/Frameworks/Accelerate.framework" ) #### end var setup ### SETUP_PLUGIN(imageio) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bvh/0000755000175000017500000000000013151044751022562 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bvh/CMakeLists.txt0000644000175000017500000000017213151044751025322 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterBVH.cpp ) SET(TARGET_ADDED_LIBRARIES osgAnimation ) #### end var setup ### SETUP_PLUGIN(bvh) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/bvh/ReaderWriterBVH.cpp0000644000175000017500000003536013151044751026234 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #include #include #include #include class BvhMotionBuilder : public osg::Referenced { public: typedef std::pair, int> JointNode; typedef std::vector JointList; BvhMotionBuilder() : _drawingFlag(0) {} virtual ~BvhMotionBuilder() {} static BvhMotionBuilder* instance() { static osg::ref_ptr s_library = new BvhMotionBuilder; return s_library.get(); } void buildHierarchy( osgDB::Input& fr, int level, osgAnimation::Bone* parent ) { bool isRecognized = false; if ( !parent ) return; if ( fr.matchSequence("OFFSET %f %f %f") ) { isRecognized = true; ++fr; osg::Vec3 offset; if ( fr.readSequence(offset) ) { // Process OFFSET section parent->setMatrixInSkeletonSpace( osg::Matrix::translate(offset) * parent->getMatrixInSkeletonSpace() ); osgAnimation::UpdateBone* updateBone = dynamic_cast( parent->getUpdateCallback() ); if ( updateBone ) { osgAnimation::StackedTransform& stack = updateBone->getStackedTransforms(); stack.push_back( new osgAnimation::StackedTranslateElement("position", offset) ); stack.push_back( new osgAnimation::StackedQuaternionElement("quaternion", osg::Quat()) ); } if ( _drawingFlag && parent->getNumParents() && level>0 ) parent->getParent(0)->addChild( createRefGeometry(offset, 0.5).get() ); } } if ( fr.matchSequence("CHANNELS %i") ) { isRecognized = true; // Process CHANNELS section int noChannels; fr[1].getInt( noChannels ); fr += 2; for ( int i=0; i bone = new osgAnimation::Bone( parent->getName()+"End" ); bone->setMatrixInSkeletonSpace( osg::Matrix::translate(offsetEndSite) * bone->getMatrixInSkeletonSpace() ); bone->setDataVariance( osg::Object::DYNAMIC ); parent->insertChild( 0, bone.get() ); if ( _drawingFlag ) parent->addChild( createRefGeometry(offsetEndSite, 0.5).get() ); } } fr.advanceOverCurrentFieldOrBlock(); } if ( fr.matchSequence("ROOT %w {") || fr.matchSequence("JOINT %w {") ) { isRecognized = true; // Process JOINT section osg::ref_ptr bone = new osgAnimation::Bone( fr[1].getStr() ); bone->setDataVariance( osg::Object::DYNAMIC ); bone->setDefaultUpdateCallback(); parent->insertChild( 0, bone.get() ); _joints.push_back( JointNode(bone, 0) ); int entry = fr[1].getNoNestedBrackets(); fr += 3; while ( !fr.eof() && fr[0].getNoNestedBrackets()>entry ) buildHierarchy( fr, entry, bone.get() ); fr.advanceOverCurrentFieldOrBlock(); } if ( !isRecognized ) { OSG_WARN << "BVH Reader: Unrecognized symbol " << fr[0].getStr() << ". Ignore current field or block." << std::endl; fr.advanceOverCurrentFieldOrBlock(); } } void buildMotion( osgDB::Input& fr, osgAnimation::Animation* anim ) { int i=0, frames=0; float frameTime=0.033f; if ( !fr.readSequence("Frames:", frames) ) { OSG_WARN << "BVH Reader: Frame number setting not found, but an unexpected " << fr[0].getStr() << ". Set to 1." << std::endl; } ++fr; if ( !fr.readSequence("Time:", frameTime) ) { OSG_WARN << "BVH Reader: Frame time setting not found, but an unexpected " << fr[0].getStr() << ". Set to 0.033 (30FPS)." << std::endl; } // Each joint has a position animating channel and an euler animating channel std::vector< osg::ref_ptr > posChannels; std::vector< osg::ref_ptr > rotChannels; for ( JointList::iterator itr=_joints.begin(); itr!=_joints.end(); ++itr ) { std::string name = itr->first->getName(); osg::ref_ptr posKey = new osgAnimation::Vec3KeyframeContainer; osg::ref_ptr posSampler = new osgAnimation::Vec3LinearSampler; osg::ref_ptr posChannel = new osgAnimation::Vec3LinearChannel( posSampler.get() ); posSampler->setKeyframeContainer( posKey.get() ); posChannel->setName( "position" ); posChannel->setTargetName( name ); osg::ref_ptr rotKey = new osgAnimation::QuatKeyframeContainer; osg::ref_ptr rotSampler = new osgAnimation::QuatSphericalLinearSampler; osg::ref_ptr rotChannel = new osgAnimation::QuatSphericalLinearChannel( rotSampler.get() ); rotSampler->setKeyframeContainer( rotKey.get() ); rotChannel->setName( "quaternion" ); rotChannel->setTargetName( name ); posChannels.push_back( posChannel ); rotChannels.push_back( rotChannel ); } // Obtain motion data from the stream while ( !fr.eof() && i(posChannel->getSampler()->getKeyframeContainer()), dynamic_cast(rotChannel->getSampler()->getKeyframeContainer()) ); } i++; } // Add valid channels to the animate object for ( unsigned int n=0; n<_joints.size(); ++n ) { if ( posChannels[n]->getOrCreateSampler()->getOrCreateKeyframeContainer()->size()>0 ) anim->addChannel( posChannels[n].get() ); if ( rotChannels[n]->getOrCreateSampler()->getOrCreateKeyframeContainer()->size()>0 ) anim->addChannel( rotChannels[n].get() ); } } osg::Group* buildBVH( std::istream& stream, const osgDB::ReaderWriter::Options* options ) { if ( options ) { if ( options->getOptionString().find("contours")!=std::string::npos ) _drawingFlag = 1; else if ( options->getOptionString().find("solids")!=std::string::npos ) _drawingFlag = 2; } osgDB::Input fr; fr.attach( &stream ); osg::ref_ptr boneroot = new osgAnimation::Bone( "Root" ); boneroot->setDefaultUpdateCallback(); osg::ref_ptr skelroot = new osgAnimation::Skeleton; skelroot->setDefaultUpdateCallback(); skelroot->insertChild( 0, boneroot.get() ); osg::ref_ptr anim = new osgAnimation::Animation; while( !fr.eof() ) { if ( fr.matchSequence("HIERARCHY") ) { ++fr; buildHierarchy( fr, 0, boneroot.get() ); } else if ( fr.matchSequence("MOTION") ) { ++fr; buildMotion( fr, anim.get() ); } else { if ( fr[0].getStr()==NULL ) continue; OSG_WARN << "BVH Reader: Unexpected beginning " << fr[0].getStr() << ", neither HIERARCHY nor MOTION. Stopped." << std::endl; break; } } #if 0 std::cout << "Bone number: " << _joints.size() << "\n"; for ( unsigned int i=0; i<_joints.size(); ++i ) { JointNode node = _joints[i]; std::cout << "Bone" << i << " " << node.first->getName() << ": "; std::cout << std::hex << node.second << std::dec << "; "; if ( node.first->getNumParents() ) std::cout << "Parent: " << node.first->getParent(0)->getName(); std::cout << "\n"; } #endif osg::Group* root = new osg::Group; osgAnimation::BasicAnimationManager* manager = new osgAnimation::BasicAnimationManager; root->addChild( skelroot.get() ); root->setUpdateCallback(manager); manager->registerAnimation( anim.get() ); manager->buildTargetReference(); manager->playAnimation( anim.get() ); _joints.clear(); return root; } protected: void alterChannel( std::string name, int& value ) { if ( name=="Xposition" ) value |= 0x01; else if ( name=="Yposition" ) value |= 0x02; else if ( name=="Zposition" ) value |= 0x04; else if ( name=="Zrotation" ) value |= 0x08; else if ( name=="Xrotation" ) value |= 0x10; else if ( name=="Yrotation" ) value |= 0x20; } void setKeyframe( osgDB::Input& fr, int ch, double time, osgAnimation::Vec3KeyframeContainer* posKey, osgAnimation::QuatKeyframeContainer* rotKey ) { if ( ch&0x07 && posKey ) // Position keyframe { float keyValue[3] = { 0.0f }; if ( ch&0x01 ) fr.readSequence( keyValue[0] ); if ( ch&0x02 ) fr.readSequence( keyValue[1] ); if ( ch&0x04 ) fr.readSequence( keyValue[2] ); osg::Vec3 vec( keyValue[0], keyValue[1], keyValue[2] ); posKey->push_back( osgAnimation::Vec3Keyframe(time, vec) ); } if ( ch&0x38 && rotKey ) // Rotation keyframe { float keyValue[3] = { 0.0f }; if ( ch&0x08 ) fr.readSequence( keyValue[2] ); if ( ch&0x10 ) fr.readSequence( keyValue[0] ); if ( ch&0x20 ) fr.readSequence( keyValue[1] ); // Note that BVH data need to concatenate the rotating matrices as Y*X*Z // So we should not create Quat directly from input values, which makes a wrong X*Y*Z osg::Matrix rotMat = osg::Matrix::rotate(osg::DegreesToRadians(keyValue[1]), osg::Vec3(0.0,1.0,0.0)) * osg::Matrix::rotate(osg::DegreesToRadians(keyValue[0]), osg::Vec3(1.0,0.0,0.0)) * osg::Matrix::rotate(osg::DegreesToRadians(keyValue[2]), osg::Vec3(0.0,0.0,1.0)); osg::Quat quat = rotMat.getRotate(); rotKey->push_back( osgAnimation::QuatKeyframe(time, quat) ); } } osg::ref_ptr createRefGeometry( osg::Vec3 p, double len ) { osg::ref_ptr geode = new osg::Geode; if ( _drawingFlag==1 ) { osg::ref_ptr geometry = new osg::Geometry; osg::ref_ptr vertices = new osg::Vec3Array; // Joint vertices->push_back( osg::Vec3(-len, 0.0, 0.0) ); vertices->push_back( osg::Vec3( len, 0.0, 0.0) ); vertices->push_back( osg::Vec3( 0.0,-len, 0.0) ); vertices->push_back( osg::Vec3( 0.0, len, 0.0) ); vertices->push_back( osg::Vec3( 0.0, 0.0,-len) ); vertices->push_back( osg::Vec3( 0.0, 0.0, len) ); // Bone vertices->push_back( osg::Vec3( 0.0, 0.0, 0.0) ); vertices->push_back( p ); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 8) ); geometry->setVertexArray( vertices.get() ); geode->addDrawable( geometry.get() ); } else if ( _drawingFlag==2 ) { osg::Quat quat; osg::ref_ptr box = new osg::Box( p*0.5, p.length(), len, len ); quat.makeRotate( osg::Vec3(1.0,0.0,0.0), p ); box->setRotation( quat ); geode->addDrawable( new osg::ShapeDrawable(box.get()) ); } return geode; } int _drawingFlag; JointList _joints; }; class ReaderWriterBVH : public osgDB::ReaderWriter { public: ReaderWriterBVH() { supportsExtension( "bvh", "Biovision motion hierarchical file" ); supportsOption( "contours","Show the skeleton with lines." ); supportsOption( "solids","Show the skeleton with solid boxes." ); } virtual const char* className() const { return "BVH Motion Reader"; } virtual ReadResult readNode(std::istream& stream, const osgDB::ReaderWriter::Options* options) const { ReadResult rr = BvhMotionBuilder::instance()->buildBVH( stream, options ); return rr; } virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension( file ); if ( !acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if ( fileName.empty() ) return ReadResult::FILE_NOT_FOUND; osgDB::ifstream stream( fileName.c_str(), std::ios::in|std::ios::binary ); if( !stream ) return ReadResult::ERROR_IN_READING_FILE; return readNode( stream, options ); } }; // Now register with Registry to instantiate the above reader/writer. REGISTER_OSGPLUGIN( bvh, ReaderWriterBVH ) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/zip/0000755000175000017500000000000013151044751022605 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/zip/ReaderWriterZIP.cpp0000644000175000017500000002071313151044751026276 0ustar albertoalberto#include #include #include #include #include #include #include "ZipArchive.h" class ReaderWriterZIP : public osgDB::ReaderWriter { public: ReaderWriterZIP() { supportsExtension("zip","Zip archive format"); osgDB::Registry::instance()->addArchiveExtension("zip"); } virtual const char* className() const { return "ZIP Database Reader/Writer"; } virtual ReadResult openArchive(const std::string& file,ArchiveStatus status, unsigned int indexBlockSize = 4096, const Options* options = NULL) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile(file, options); if (fileName.empty()) { //we do not support writing so the file must exist return ReadResult::FILE_NOT_FOUND; } // copy the incoming options if possible so that plugin options can be applied to files // inside the archive osg::ref_ptr local_options = options? options->cloneOptions() : new osgDB::ReaderWriter::Options; osg::ref_ptr archive = new ZipArchive; if (!archive->open(fileName, osgDB::ReaderWriter::READ, local_options.get())) { return ReadResult(ReadResult::FILE_NOT_HANDLED); } return archive.get(); } /** open an archive for reading.*/ virtual ReadResult openArchive(std::istream& fin, const Options* options) const { osg::ref_ptr archive = new ZipArchive; if (!archive->open(fin, options)) { return ReadResult(ReadResult::FILE_NOT_HANDLED); } return archive.get(); } osgDB::ReaderWriter::ReadResult readNodeFromArchive(osgDB::Archive& archive, const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult result(osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND); if (!archive.getMasterFileName().empty()) { result = archive.readNode(archive.getMasterFileName(), options); } else { osgDB::Archive::FileNameList fileNameList; if (archive.getFileNames(fileNameList)) { typedef std::list< osg::ref_ptr > Nodes; Nodes nodes; for(osgDB::Archive::FileNameList::iterator itr = fileNameList.begin(); itr != fileNameList.end(); ++itr) { result = archive.readNode(*itr, options); if (result.validNode()) nodes.push_back(result.getNode()); } if (!nodes.empty()) { if (nodes.size()==1) { result = osgDB::ReaderWriter::ReadResult(nodes.front().get()); } else { osg::ref_ptr group = new osg::Group; for(Nodes::iterator itr = nodes.begin(); itr != nodes.end(); ++itr) { group->addChild(itr->get()); } result = osgDB::ReaderWriter::ReadResult(group.get()); } } } } return result; } virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult result = openArchive(file, osgDB::Archive::READ); if (!result.validArchive()) return result; osg::ref_ptr archive = result.getArchive(); if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)) { // register the archive so that it is cached for future use. osgDB::Registry::instance()->addToArchiveCache(file, archive.get()); } // copy the incoming options if possible so that plugin options can be applied to files // inside the archive osg::ref_ptr local_options = options? options->cloneOptions() : new osgDB::ReaderWriter::Options; local_options->setDatabasePath(file); return readNodeFromArchive(*archive, local_options.get()); } virtual ReadResult readNode(std::istream& fin,const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult result = openArchive(fin, options); if (!result.validArchive()) return result; osg::ref_ptr archive = result.getArchive(); // copy the incoming options if possible so that plugin options can be applied to files // inside the archive osg::ref_ptr local_options = options? options->cloneOptions() : new osgDB::ReaderWriter::Options; return readNodeFromArchive(*archive, local_options.get()); } osgDB::ReaderWriter::ReadResult readImageFromArchive(osgDB::Archive& archive, const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult result(osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND); if (!archive.getMasterFileName().empty()) { result = archive.readImage(archive.getMasterFileName(), options); } else { osgDB::Archive::FileNameList fileNameList; if (archive.getFileNames(fileNameList)) { for(osgDB::Archive::FileNameList::iterator itr = fileNameList.begin(); itr != fileNameList.end() && !result.validImage(); ++itr) { result = archive.readImage(*itr, options); } } } return result; } virtual ReadResult readImage(const std::string& file,const Options* options) const { osgDB::ReaderWriter::ReadResult result = openArchive(file, osgDB::Archive::READ); if (!result.validArchive()) return result; osg::ref_ptr archive = result.getArchive(); if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)) { // register the archive so that it is cached for future use. osgDB::Registry::instance()->addToArchiveCache(file, archive.get()); } // copy the incoming options if possible so that plugin options can be applied to files // inside the archive osg::ref_ptr local_options = options? options->cloneOptions() : new osgDB::ReaderWriter::Options; local_options->setDatabasePath(file); return readImageFromArchive(*archive, local_options.get()); } virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult result = openArchive(fin, options); if (!result.validArchive()) return result; osg::ref_ptr archive = result.getArchive(); // copy the incoming options if possible so that plugin options can be applied to files // inside the archive osg::ref_ptr local_options = options? options->cloneOptions() : new osgDB::ReaderWriter::Options; return readImageFromArchive(*archive, local_options.get()); } }; // now register with sgRegistry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(zip, ReaderWriterZIP) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/zip/unzip.h0000644000175000017500000002546413151044751024136 0ustar albertoalberto // UNZIPPING functions -- for unzipping. // This file is a repackaged form of extracts from the zlib code available // at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original // copyright notice may be found in unzip.cpp. The repackaging was done // by Lucian Wischik to simplify and extend its use in Windows/C++. Also // encryption and unicode filenames have been added. #ifndef _unzip_H #define _unzip_H // #ifdef ZIP_STD #include #include #include #include #ifdef _MSC_VER #include // microsoft puts it here #else #include #endif #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) #include #define lumkdir(t) (_mkdir(t)) #else #include #define lumkdir(t) (mkdir(t,0755)) #endif #include #include // typedef unsigned short WORD; #define _tcslen strlen #define _tcsicmp stricmp #define _tcsncpy strncpy #define _tcsstr strstr #define INVALID_HANDLE_VALUE 0 #ifndef _T #define _T(s) s #endif #ifndef S_IWUSR #define S_IWUSR 0000200 #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) #endif // #else #include #include #include #include #include #endif #ifdef ZIP_STD #include #define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name #ifndef MAX_PATH #define MAX_PATH 1024 #endif typedef unsigned long DWORD; typedef char TCHAR; typedef FILE* HANDLE; typedef time_t FILETIME; #endif #ifndef _zip_H DECLARE_HANDLE(HZIP); #endif // An HZIP identifies a zip file that has been opened typedef DWORD ZRESULT; // return codes from any of the zip functions. Listed later. typedef struct { int index; // index of this file within the zip TCHAR name[MAX_PATH]; // filename within the zip DWORD attr; // attributes, as in GetFileAttributes. FILETIME atime,ctime,mtime;// access, create, modify filetimes long comp_size; // sizes of item, compressed and uncompressed. These long unc_size; // may be -1 if not yet known (e.g. being streamed in) } ZIPENTRY; HZIP OpenZip(const TCHAR *fn, const char *password); HZIP OpenZip(void *z,unsigned int len, const char *password); HZIP OpenZipHandle(HANDLE h, const char *password); // OpenZip - opens a zip file and returns a handle with which you can // subsequently examine its contents. You can open a zip file from: // from a pipe: OpenZipHandle(hpipe_read,0); // from a file (by handle): OpenZipHandle(hfile,0); // from a file (by name): OpenZip("c:\\test.zip","password"); // from a memory block: OpenZip(bufstart, buflen,0); // If the file is opened through a pipe, then items may only be // accessed in increasing order, and an item may only be unzipped once, // although GetZipItem can be called immediately before and after unzipping // it. If it's opened in any other way, then full random access is possible. // Note: pipe input is not yet implemented. // Note: zip passwords are ascii, not unicode. // Note: for windows-ce, you cannot close the handle until after CloseZip. // but for real windows, the zip makes its own copy of your handle, so you // can close yours anytime. ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze); // GetZipItem - call this to get information about an item in the zip. // If index is -1 and the file wasn't opened through a pipe, // then it returns information about the whole zipfile // (and in particular ze.index returns the number of index items). // Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) // See below for notes on what happens when you unzip such an item. // Note: if you are opening the zip through a pipe, then random access // is not possible and GetZipItem(-1) fails and you can't discover the number // of items except by calling GetZipItem on each one of them in turn, // starting at 0, until eventually the call fails. Also, in the event that // you are opening through a pipe and the zip was itself created into a pipe, // then then comp_size and sometimes unc_size as well may not be known until // after the item has been unzipped. ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); // FindZipItem - finds an item by name. ic means 'insensitive to case'. // It returns the index of the item, and returns information about it. // If nothing was found, then index is set to -1 and the function returns // an error code. ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn); ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len); ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h); // UnzipItem - given an index to an item, unzips it. You can unzip to: // to a pipe: UnzipItemHandle(hz,i, hpipe_write); // to a file (by handle): UnzipItemHandle(hz,i, hfile); // to a file (by name): UnzipItem(hz,i, ze.name); // to a memory block: UnzipItem(hz,i, buf,buflen); // In the final case, if the buffer isn't large enough to hold it all, // then the return code indicates that more is yet to come. If it was // large enough, and you want to know precisely how big, GetZipItem. // Note: zip files are normally stored with relative pathnames. If you // unzip with ZIP_FILENAME a relative pathname then the item gets created // relative to the current directory - it first ensures that all necessary // subdirectories have been created. Also, the item may itself be a directory. // If you unzip a directory with ZIP_FILENAME, then the directory gets created. // If you unzip it to a handle or a memory block, then nothing gets created // and it emits 0 bytes. ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir); // if unzipping to a filename, and it's a relative filename, then it will be relative to here. // (defaults to current-directory). ZRESULT CloseZip(HZIP hz); // CloseZip - the zip handle must be closed with this function. unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); // FormatZipMessage - given an error code, formats it as a string. // It returns the length of the error message. If buf/len points // to a real buffer, then it also writes as much as possible into there. // These are the result codes: #define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, #define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. // The following come from general system stuff (e.g. files not openable) #define ZR_GENMASK 0x0000FF00 #define ZR_NODUPH 0x00000100 // couldn't duplicate the handle #define ZR_NOFILE 0x00000200 // couldn't create/open the file #define ZR_NOALLOC 0x00000300 // failed to allocate some resource #define ZR_WRITE 0x00000400 // a general error writing to the file #define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip #define ZR_MORE 0x00000600 // there's still more data to be unzipped #define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile #define ZR_READ 0x00000800 // a general error reading the file #define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file // The following come from mistakes on the part of the caller #define ZR_CALLERMASK 0x00FF0000 #define ZR_ARGS 0x00010000 // general mistake with the arguments #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't #define ZR_MEMSIZE 0x00030000 // the memory size is too small #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function #define ZR_ENDED 0x00050000 // the zip creation has already been closed #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip // The following come from bugs within the zip library itself #define ZR_BUGMASK 0xFF000000 #define ZR_NOTINITED 0x01000000 // initialisation didn't work #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code // e.g. // // SetCurrentDirectory("c:\\docs\\stuff"); // HZIP hz = OpenZip("c:\\stuff.zip",0); // ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; // for (int i=0; i #include #include #include #include "unzip.h" class ZipArchive : public osgDB::Archive { public: ZipArchive(); virtual ~ZipArchive(); virtual const char* libraryName() const { return "osgDB"; } virtual const char* className() const { return "ZipArchive"; } virtual bool acceptsExtension(const std::string& /*extension*/) const { return true; } /** close the archive.*/ virtual void close(); /** open the archive.*/ virtual bool open(const std::string& filename, ArchiveStatus status, const osgDB::ReaderWriter::Options* options); /** open the archive for reading.*/ virtual bool open(std::istream& fin, const osgDB::ReaderWriter::Options* options); /** return true if file exists in archive.*/ virtual bool fileExists(const std::string& filename) const; /** Get the filename that refers to the archived file on disk*/ virtual std::string getArchiveFileName() const; /** Get the file name which represents the master file recorded in the Archive.*/ virtual std::string getMasterFileName() const; /** Get the full list of file names available in the archive.*/ virtual bool getFileNames(osgDB::Archive::FileNameList& fileNameList) const; /** return type of file. */ virtual osgDB::FileType getFileType(const std::string& filename) const; /** return the contents of a directory. * returns an empty array on any error.*/ virtual osgDB::DirectoryContents getDirectoryContents(const std::string& dirName) const; virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& /*fileName*/, const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::ReadResult readHeightField(const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& /*fileName*/, const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::ReadResult readShader(const std::string& /*fileName*/, const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::WriteResult writeObject(const osg::Object& /*obj*/, const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::WriteResult writeImage(const osg::Image& /*image*/, const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::WriteResult writeHeightField(const osg::HeightField& /*heightField*/, const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::WriteResult writeNode(const osg::Node& /*node*/, const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; virtual osgDB::ReaderWriter::WriteResult writeShader(const osg::Shader& /*shader*/, const std::string& /*fileName*/,const osgDB::ReaderWriter::Options* =NULL) const; protected: osgDB::ReaderWriter* ReadFromZipEntry(const ZIPENTRY* ze, const osgDB::ReaderWriter::Options* options, std::stringstream& streamIn) const; void IndexZipFiles(HZIP hz); const ZIPENTRY* GetZipEntry(const std::string& filename) const; ZIPENTRY* GetZipEntry(const std::string& filename); std::string ReadPassword(const osgDB::ReaderWriter::Options* options) const; bool CheckZipErrorCode(ZRESULT result) const; private: typedef std::pair ZipEntryMapping; typedef std::map ZipEntryMap; std::string _filename, _password, _membuffer; OpenThreads::Mutex _zipMutex; bool _zipLoaded; ZipEntryMap _zipIndex; ZIPENTRY _mainRecord; struct PerThreadData { HZIP _zipHandle; }; typedef std::map PerThreadDataMap; PerThreadDataMap _perThreadData; const PerThreadData& getData() const; const PerThreadData& getDataNoLock() const; }; #endif //OSGDB_ZIPARCHIVE OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/zip/ZipArchive.cpp0000644000175000017500000004643513151044751025371 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include "ZipArchive.h" #include #include #include #include #include #include #include #include #include "unzip.h" #if !defined(S_ISDIR) # if defined( _S_IFDIR) && !defined( __S_IFDIR) # define __S_IFDIR _S_IFDIR # endif # define S_ISDIR(mode) (mode&__S_IFDIR) #endif #ifndef S_ISREG #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) #endif ZipArchive::ZipArchive() : _zipLoaded( false ) { } ZipArchive::~ZipArchive() { } /** close the archive (on all threads) */ void ZipArchive::close() { if ( _zipLoaded ) { OpenThreads::ScopedLock exclusive(_zipMutex); if ( _zipLoaded ) { // close the file (on one thread since it's a shared file) const PerThreadData& data = getDataNoLock(); CloseZip( data._zipHandle ); // clear out the file handles _perThreadData.clear(); // clear out the index. _zipIndex.clear(); _zipLoaded = false; } } } /** return true if file exists in archive.*/ bool ZipArchive::fileExists(const std::string& filename) const { return GetZipEntry(filename) != NULL; } /** Get the file name which represents the master file recorded in the Archive.*/ std::string ZipArchive::getMasterFileName() const { return std::string(); } std::string ZipArchive::getArchiveFileName() const { std::string result; if( _zipLoaded ) { result = _mainRecord.name; } return result; } /** Get the full list of file names available in the archive.*/ bool ZipArchive::getFileNames(osgDB::Archive::FileNameList& fileNameList) const { if(_zipLoaded) { ZipEntryMap::const_iterator iter = _zipIndex.begin(); for(;iter != _zipIndex.end(); ++iter) { fileNameList.push_back((*iter).first); } return true; } else { return false; } } bool ZipArchive::open(const std::string& file, ArchiveStatus status, const osgDB::ReaderWriter::Options* options) { if ( !_zipLoaded ) { // exclusive lock when we open for the first time: OpenThreads::ScopedLock exclusiveLock( _zipMutex ); if ( !_zipLoaded ) // double-check avoids race condition { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; // save the filename + password so other threads can open the file _filename = osgDB::findDataFile( file, options ); if (_filename.empty()) return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND; _password = ReadPassword(options); // open the zip file in this thread: const PerThreadData& data = getDataNoLock(); // establish a shared (read-only) index: if ( data._zipHandle != NULL ) { IndexZipFiles( data._zipHandle ); _zipLoaded = true; } } } return _zipLoaded; } bool ZipArchive::open(std::istream& fin, const osgDB::ReaderWriter::Options* options) { if ( !_zipLoaded ) { // exclusive lock when we open for the first time: OpenThreads::ScopedLock exclusive(_zipMutex); if ( !_zipLoaded ) // double-check avoids race condition { osgDB::ReaderWriter::ReadResult result = osgDB::ReaderWriter::ReadResult(osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED); if (fin.fail()) return false; // read the stream into a memory buffer that we'll keep around for any other // threads that want to open the file std::stringstream buf; buf << fin.rdbuf(); _membuffer = buf.str(); _password = ReadPassword(options); // open on this thread: const PerThreadData& data = getDataNoLock(); if ( data._zipHandle != NULL ) { IndexZipFiles( data._zipHandle ); _zipLoaded = true; } } } return _zipLoaded; } osgDB::ReaderWriter::ReadResult ZipArchive::readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; std::string ext = osgDB::getLowerCaseFileExtension(file); if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; const ZIPENTRY* ze = GetZipEntry(file); if(ze != NULL) { std::stringstream buffer; osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer); if (rw != NULL) { // Setup appropriate options osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new osgDB::ReaderWriter::Options; local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name)); osgDB::ReaderWriter::ReadResult readResult = rw->readObject(buffer,local_opt.get()); if (readResult.success()) { return readResult; } } } return rresult; } osgDB::ReaderWriter::ReadResult ZipArchive::readImage(const std::string& file,const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; std::string ext = osgDB::getLowerCaseFileExtension(file); if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; const ZIPENTRY* ze = GetZipEntry(file); if(ze != NULL) { std::stringstream buffer; osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer); if (rw != NULL) { // Setup appropriate options osg::ref_ptr local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new osgDB::ReaderWriter::Options; local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name)); osgDB::ReaderWriter::ReadResult readResult = rw->readImage(buffer,local_opt.get()); if (readResult.success()) { return readResult; } } } return rresult; } osgDB::ReaderWriter::ReadResult ZipArchive::readHeightField(const std::string& file,const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; std::string ext = osgDB::getLowerCaseFileExtension(file); if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; const ZIPENTRY* ze = GetZipEntry(file); if(ze != NULL) { std::stringstream buffer; osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer); if (rw != NULL) { // Setup appropriate options osg::ref_ptr local_opt = options ? options->cloneOptions() : new osgDB::ReaderWriter::Options; local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name)); osgDB::ReaderWriter::ReadResult readResult = rw->readObject(buffer,local_opt.get()); if (readResult.success()) { return readResult; } } } return rresult; } osgDB::ReaderWriter::ReadResult ZipArchive::readNode(const std::string& file,const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; std::string ext = osgDB::getLowerCaseFileExtension(file); if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; const ZIPENTRY* ze = GetZipEntry(file); if(ze != NULL) { std::stringstream buffer; osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer); if (rw != NULL) { // Setup appropriate options osg::ref_ptr local_opt = options ? options->cloneOptions() : new osgDB::ReaderWriter::Options; local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name)); osgDB::ReaderWriter::ReadResult readResult = rw->readNode(buffer,local_opt.get()); if (readResult.success()) { return readResult; } } } return rresult; } osgDB::ReaderWriter::ReadResult ZipArchive::readShader(const std::string& file,const osgDB::ReaderWriter::Options* options) const { osgDB::ReaderWriter::ReadResult rresult = osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; std::string ext = osgDB::getLowerCaseFileExtension(file); if (!_zipLoaded || !acceptsExtension(ext)) return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; const ZIPENTRY* ze = GetZipEntry(file); if(ze != NULL) { std::stringstream buffer; osgDB::ReaderWriter* rw = ReadFromZipEntry(ze, options, buffer); if (rw != NULL) { // Setup appropriate options osg::ref_ptr local_opt = options ? options->cloneOptions() : new osgDB::ReaderWriter::Options; local_opt->setPluginStringData("STREAM_FILENAME", osgDB::getSimpleFileName(ze->name)); osgDB::ReaderWriter::ReadResult readResult = rw->readShader(buffer,local_opt.get()); if (readResult.success()) { return readResult; } } } return rresult; } osgDB::ReaderWriter::WriteResult ZipArchive::writeObject(const osg::Object& /*obj*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const { return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED); } osgDB::ReaderWriter::WriteResult ZipArchive::writeImage(const osg::Image& /*image*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const { return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED); } osgDB::ReaderWriter::WriteResult ZipArchive::writeHeightField(const osg::HeightField& /*heightField*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const { return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED); } osgDB::ReaderWriter::WriteResult ZipArchive::writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const { return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED); } osgDB::ReaderWriter::WriteResult ZipArchive::writeShader(const osg::Shader& /*shader*/,const std::string& /*fileName*/,const osgDB::ReaderWriter::Options*) const { return osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED); } osgDB::ReaderWriter* ZipArchive::ReadFromZipEntry(const ZIPENTRY* ze, const osgDB::ReaderWriter::Options* options, std::stringstream& buffer) const { if (ze != 0) { char* ibuf = new (std::nothrow) char[ze->unc_size]; if (ibuf) { // fetch the handle for the current thread: const PerThreadData& data = getData(); if ( data._zipHandle != NULL ) { ZRESULT result = UnzipItem(data._zipHandle, ze->index, ibuf, ze->unc_size); bool unzipSuccesful = CheckZipErrorCode(result); if(unzipSuccesful) { buffer.write(ibuf,ze->unc_size); } delete[] ibuf; std::string file_ext = osgDB::getFileExtension(ze->name); osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(file_ext); if (rw != NULL) { return rw; } } } else { //std::cout << "Error- failed to allocate enough memory to unzip file '" << ze->name << ", with size '" << ze->unc_size << std::endl; } } return NULL; } void CleanupFileString(std::string& strFileOrDir) { if (strFileOrDir.empty()) { return; } // convert all separators to unix-style for conformity for (unsigned int i = 0; i < strFileOrDir.length(); ++i) { if (strFileOrDir[i] == '\\') { strFileOrDir[i] = '/'; } } // get rid of trailing separators if (strFileOrDir[strFileOrDir.length()-1] == '/') { strFileOrDir = strFileOrDir.substr(0, strFileOrDir.length()-1); } //add a beginning separator if(strFileOrDir[0] != '/') { strFileOrDir.insert(0, "/"); } } void ZipArchive::IndexZipFiles(HZIP hz) { if(hz != NULL && !_zipLoaded) { //mZipRecord = hz; GetZipItem(hz, -1, &_mainRecord); int numitems = _mainRecord.index; // Now loop through each file in zip for (int i = 0; i < numitems; i++) { ZIPENTRY* ze = new ZIPENTRY(); GetZipItem(hz, i, ze); std::string name = ze->name; CleanupFileString(name); if(!name.empty()) { _zipIndex.insert(ZipEntryMapping(name, ze)); } } } } ZIPENTRY* ZipArchive::GetZipEntry(const std::string& filename) { ZIPENTRY* ze = NULL; std::string fileToLoad = filename; CleanupFileString(fileToLoad); ZipEntryMap::iterator iter = _zipIndex.find(fileToLoad); if(iter != _zipIndex.end()) { ze = (*iter).second; } return ze; } const ZIPENTRY* ZipArchive::GetZipEntry(const std::string& filename) const { ZIPENTRY* ze = NULL; std::string fileToLoad = filename; CleanupFileString(fileToLoad); ZipEntryMap::const_iterator iter = _zipIndex.find(fileToLoad); if(iter != _zipIndex.end()) { ze = (*iter).second; } return ze; } osgDB::FileType ZipArchive::getFileType(const std::string& filename) const { const ZIPENTRY* ze = GetZipEntry(filename); if(ze != NULL) { #ifdef ZIP_STD if (ze->attr & S_IFDIR) #else if (ze->attr & FILE_ATTRIBUTE_DIRECTORY) #endif { return osgDB::DIRECTORY; } else { return osgDB::REGULAR_FILE; } } return osgDB::FILE_NOT_FOUND; } osgDB::DirectoryContents ZipArchive::getDirectoryContents(const std::string& dirName) const { osgDB::DirectoryContents dirContents; ZipEntryMap::const_iterator iter = _zipIndex.begin(); ZipEntryMap::const_iterator iterEnd = _zipIndex.end(); for(; iter != iterEnd; ++iter) { std::string searchPath = dirName; CleanupFileString(searchPath); if(iter->first.size() > searchPath.size()) { size_t endSubElement = iter->first.find(searchPath); //we match the whole string in the beginning of the path if(endSubElement == 0) { std::string remainingFile = iter->first.substr(searchPath.size() + 1, std::string::npos); size_t endFileToken = remainingFile.find_first_of('/'); if(endFileToken == std::string::npos) { dirContents.push_back(remainingFile); } } } } return dirContents; } std::string ZipArchive::ReadPassword(const osgDB::ReaderWriter::Options* options) const { //try pulling it off the options first std::string password = ""; if(options != NULL) { const osgDB::AuthenticationMap* credentials = options->getAuthenticationMap(); if(credentials != NULL) { const osgDB::AuthenticationDetails* details = credentials->getAuthenticationDetails("ZipPlugin"); if(details != NULL) { password = details->password; } } } //if no password, try the registry if(password.empty()) { osgDB::Registry* reg = osgDB::Registry::instance(); if(reg != NULL) { const osgDB::AuthenticationMap* credentials = reg->getAuthenticationMap(); if(credentials != NULL) { const osgDB::AuthenticationDetails* details = credentials->getAuthenticationDetails("ZipPlugin"); if(details != NULL) { password = details->password; } } } } return password; } bool ZipArchive::CheckZipErrorCode(ZRESULT result) const { if(result == ZR_OK) { return true; } else { unsigned buf_size = 1025; char* buf = new (std::nothrow) char[buf_size]; buf[buf_size - 1] = 0; if (buf) { FormatZipMessage(result, buf, buf_size - 1); //print error message //sprintf(buf, "%s"); OSG_WARN << "Error loading zip file: " << getArchiveFileName() << ", Zip loader returned error: " << buf << "\n"; delete [] buf; } return false; } } const ZipArchive::PerThreadData& ZipArchive::getData() const { OpenThreads::ScopedLock exclusive( const_cast(this)->_zipMutex ); return getDataNoLock(); } const ZipArchive::PerThreadData& ZipArchive::getDataNoLock() const { // get/create data for the currently running thread: OpenThreads::Thread* current = OpenThreads::Thread::CurrentThread(); PerThreadDataMap::const_iterator i = _perThreadData.find( current ); if ( i == _perThreadData.end() || i->second._zipHandle == NULL ) { // cache pattern: cast to const for caching purposes ZipArchive* ncThis = const_cast(this); // data does not already exist, so open the ZIP with a handle exclusively for this thread: PerThreadData& data = ncThis->_perThreadData[current]; if ( !_filename.empty() ) { data._zipHandle = OpenZip( _filename.c_str(), _password.c_str() ); } else if ( !_membuffer.empty() ) { data._zipHandle = OpenZip( (void*)_membuffer.c_str(), _membuffer.length(), _password.c_str() ); } else { data._zipHandle = NULL; } return data; } else { return i->second; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/zip/CMakeLists.txt0000644000175000017500000000024613151044751025347 0ustar albertoalbertoSET(TARGET_SRC unzip.cpp ZipArchive.cpp ReaderWriterZIP.cpp ) SET(TARGET_H unzip.h ZipArchive.h ) ADD_DEFINITIONS(-DZIP_STD) SETUP_PLUGIN(zip) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/zip/unzip.cpp0000644000175000017500000045043313151044751024467 0ustar albertoalberto// THIS FILE is almost entirely based upon code by Jean-loup Gailly // and Mark Adler, and subsequent modifications by Lucian Wischik. // It has been modified further by Neil Hughes. // The modifications were: a minor reorganisation of the include files // referenced within the cpp files, moving them to the .h file to ease // compilation with OpenSceneGraph - found at http://www.openscenegraph.org/projects/osg // Providing alternative to _tcsncpy_s for ZIP_STD compilations. // Provided alternative to _tsprintf code for ZIP_STD compilations. // The original copyright text and comments as recorded in // Lucian Wischik's cpp follows. // // THIS FILE is almost entirely based upon code by Jean-loup Gailly // and Mark Adler. It has been modified by Lucian Wischik. // The modifications were: incorporate the bugfixes of 1.1.4, allow // unzipping to/from handles/pipes/files/memory, encryption, unicode, // a windowsish api, and putting everything into a single .cpp file. // The original code may be found at http://www.gzip.org/zlib/ // The original copyright text follows. // // // // zlib.h -- interface of the 'zlib' general purpose compression library // version 1.1.3, July 9th, 1998 // // Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // // Jean-loup Gailly Mark Adler // jloup@gzip.org madler@alumni.caltech.edu // // // The data format used by the zlib library is described by RFCs (Request for // Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt // (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). // // // The 'zlib' compression library provides in-memory compression and // decompression functions, including integrity checks of the uncompressed // data. This version of the library supports only one compression method // (deflation) but other algorithms will be added later and will have the same // stream interface. // // Compression can be done in a single step if the buffers are large // enough (for example if an input file is mmap'ed), or can be done by // repeated calls of the compression function. In the latter case, the // application must provide more input and/or consume the output // (providing more output space) before each call. // // The library also supports reading and writing files in gzip (.gz) format // with an interface similar to that of stdio. // // The library does not install any signal handler. The decoder checks // the consistency of the compressed data, so the library should never // crash even in case of corrupted input. // // for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip // PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip //#ifdef ZIP_STD //#include //#include //#include //#include //#ifdef _MSC_VER //#include // microsoft puts it here //#else //#include //#endif //#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) //#include //#define lumkdir(t) (mkdir(t)) //#else //#include //#define lumkdir(t) (mkdir(t,0755)) //#endif //#include //#include //#include "unzip.h" //// //typedef unsigned short WORD; //#define _tcslen strlen //#define _tcsicmp stricmp //#define _tcsncpy strncpy //#define _tcsstr strstr //#define INVALID_HANDLE_VALUE 0 //#ifndef _T //#define _T(s) s //#endif //#ifndef S_IWUSR //#define S_IWUSR 0000200 //#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) //#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) //#endif //// //#else //#include //#include //#include //#include //#include //#include "unzip.h" //#endif //// #include "unzip.h" #ifndef ZIP_STD #ifdef UNICODE #define _tsprintf swprintf #else #define _tsprintf sprintf_s #endif #endif // workaround for Windows warnings. #if defined(_MSC_VER) #define FILENO _fileno #define GETCWD _getcwd #else #define FILENO fileno #define GETCWD getcwd #endif #define ZIP_HANDLE 1 #define ZIP_FILENAME 2 #define ZIP_MEMORY 3 #define zmalloc(len) malloc(len) #define zfree(p) free(p) typedef unsigned long lutime_t; // define it ourselves since we don't include time.h /* void *zmalloc(unsigned int len) { char *buf = new char[len+32]; for (int i=0; i<16; i++) { buf[i]=i; buf[len+31-i]=i; } *((unsigned int*)buf) = len; char c[1000]; wsprintf(c,"malloc 0x%lx - %lu",buf+16,len); OutputDebugString(c); return buf+16; } void zfree(void *buf) { char c[1000]; wsprintf(c,"free 0x%lx",buf); OutputDebugString(c); char *p = ((char*)buf)-16; unsigned int len = *((unsigned int*)p); bool blown=false; for (int i=0; i<16; i++) { char lo = p[i]; char hi = p[len+31-i]; if (hi!=i || (lo!=i && i>4)) blown=true; } if (blown) { OutputDebugString("BLOWN!!!"); } delete[] p; } */ typedef struct tm_unz_s { unsigned int tm_sec; // seconds after the minute - [0,59] unsigned int tm_min; // minutes after the hour - [0,59] unsigned int tm_hour; // hours since midnight - [0,23] unsigned int tm_mday; // day of the month - [1,31] unsigned int tm_mon; // months since January - [0,11] unsigned int tm_year; // years - [1980..2044] } tm_unz; // ---------------------------------------------------------------------- // some windows<->linux portability things #ifdef ZIP_STD DWORD GetFilePosU(HANDLE hfout) { struct stat st; fstat(FILENO(hfout),&st); if ((st.st_mode&S_IFREG)==0) return 0xFFFFFFFF; return ftell(hfout); } bool FileExists(const TCHAR *fn) { struct stat st; int res=stat(fn,&st); return (res==0); } FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime) { struct tm t; t.tm_year = (WORD)(((dosdate>>9)&0x7f) + 1980 - 1900); t.tm_isdst = -1; t.tm_mon = (WORD)(((dosdate>>5)&0xf) - 1); t.tm_mday = (WORD)(dosdate&0x1f); t.tm_hour = (WORD)((dostime>>11)&0x1f); t.tm_min = (WORD)((dostime>>5)&0x3f); t.tm_sec = (WORD)((dostime&0x1f)*2); time_t t2 = mktime(&t); return t2; } void LocalFileTimeToFileTime(FILETIME *lft, FILETIME *ft) { *ft = *lft; } FILETIME timet2filetime(const lutime_t t) { return t; } #else // ---------------------------------------------------------------------- DWORD GetFilePosU(HANDLE hfout) { return SetFilePointer(hfout,0,0,FILE_CURRENT); } FILETIME timet2filetime(const lutime_t t) { LONGLONG i = Int32x32To64(t,10000000) + 116444736000000000LL; FILETIME ft; ft.dwLowDateTime = (DWORD) i; ft.dwHighDateTime = (DWORD)(i >>32); return ft; } FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime) { // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 SYSTEMTIME st; st.wYear = (WORD)(((dosdate>>9)&0x7f) + 1980); st.wMonth = (WORD)((dosdate>>5)&0xf); st.wDay = (WORD)(dosdate&0x1f); st.wHour = (WORD)((dostime>>11)&0x1f); st.wMinute = (WORD)((dostime>>5)&0x3f); st.wSecond = (WORD)((dostime&0x1f)*2); st.wMilliseconds = 0; FILETIME ft; SystemTimeToFileTime(&st,&ft); return ft; } bool FileExists(const TCHAR *fn) { return (GetFileAttributes(fn)!=0xFFFFFFFF); } #endif // ---------------------------------------------------------------------- // unz_global_info structure contain global data about the ZIPfile typedef struct unz_global_info_s { unz_global_info_s(): number_entry(0), size_comment(0) {} unsigned long number_entry; // total number of entries in the central dir on this disk unsigned long size_comment; // size of the global comment of the zipfile } unz_global_info; // unz_file_info contain information about a file in the zipfile typedef struct unz_file_info_s { unsigned long version; // version made by 2 bytes unsigned long version_needed; // version needed to extract 2 bytes unsigned long flag; // general purpose bit flag 2 bytes unsigned long compression_method; // compression method 2 bytes unsigned long dosDate; // last mod file date in Dos fmt 4 bytes unsigned long crc; // crc-32 4 bytes unsigned long compressed_size; // compressed size 4 bytes unsigned long uncompressed_size; // uncompressed size 4 bytes unsigned long size_filename; // filename length 2 bytes unsigned long size_file_extra; // extra field length 2 bytes unsigned long size_file_comment; // file comment length 2 bytes unsigned long disk_num_start; // disk number start 2 bytes unsigned long internal_fa; // internal file attributes 2 bytes unsigned long external_fa; // external file attributes 4 bytes tm_unz tmu_date; } unz_file_info; #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) #define UNZ_PASSWORD (-106) #define ZLIB_VERSION "1.1.3" // Allowed flush values; see deflate() for details #define Z_NO_FLUSH 0 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 // compression levels #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) // compression strategy; see deflateInit2() for details #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_DEFAULT_STRATEGY 0 // Possible values of the data_type field #define Z_BINARY 0 #define Z_ASCII 1 #define Z_UNKNOWN 2 // The deflate compression method (the only one supported in this version) #define Z_DEFLATED 8 // for initializing zalloc, zfree, opaque #define Z_NULL 0 // case sensitivity when searching for filenames #define CASE_SENSITIVE 1 #define CASE_INSENSITIVE 2 // Return codes for the compression/decompression functions. Negative // values are errors, positive values are used for special but normal events. #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) // Basic data types typedef unsigned char Byte; // 8 bits typedef unsigned int uInt; // 16 bits or more typedef unsigned long uLong; // 32 bits or more typedef void *voidpf; typedef void *voidp; typedef long z_off_t; typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size); typedef void (*free_func) (voidpf opaque, voidpf address); struct internal_state; typedef struct z_stream_s { Byte *next_in; // next input byte uInt avail_in; // number of bytes available at next_in uLong total_in; // total nb of input bytes read so far Byte *next_out; // next output byte should be put there uInt avail_out; // remaining free space at next_out uLong total_out; // total nb of bytes output so far char *msg; // last error message, NULL if no error struct internal_state *state; // not visible by applications alloc_func zalloc; // used to allocate the internal state free_func zfree; // used to free the internal state voidpf opaque; // private data object passed to zalloc and zfree int data_type; // best guess about the data type: ascii or binary uLong adler; // adler32 value of the uncompressed data uLong reserved; // reserved for future use } z_stream; typedef z_stream *z_streamp; // The application must update next_in and avail_in when avail_in has // dropped to zero. It must update next_out and avail_out when avail_out // has dropped to zero. The application must initialize zalloc, zfree and // opaque before calling the init function. All other fields are set by the // compression library and must not be updated by the application. // // The opaque value provided by the application will be passed as the first // parameter for calls of zalloc and zfree. This can be useful for custom // memory management. The compression library attaches no meaning to the // opaque value. // // zalloc must return Z_NULL if there is not enough memory for the object. // If zlib is used in a multi-threaded application, zalloc and zfree must be // thread safe. // // The fields total_in and total_out can be used for statistics or // progress reports. After compression, total_in holds the total size of // the uncompressed data and may be saved for use in the decompressor // (particularly if the decompressor wants to decompress everything in // a single step). // // basic functions const char *zlibVersion (); // The application can compare zlibVersion and ZLIB_VERSION for consistency. // If the first character differs, the library code actually used is // not compatible with the zlib.h header file used by the application. // This check is automatically made by inflateInit. int inflate (z_streamp strm, int flush); // // inflate decompresses as much data as possible, and stops when the input // buffer becomes empty or the output buffer becomes full. It may some // introduce some output latency (reading input without producing any output) // except when forced to flush. // // The detailed semantics are as follows. inflate performs one or both of the // following actions: // // - Decompress more input starting at next_in and update next_in and avail_in // accordingly. If not all input can be processed (because there is not // enough room in the output buffer), next_in is updated and processing // will resume at this point for the next call of inflate(). // // - Provide more output starting at next_out and update next_out and avail_out // accordingly. inflate() provides as much output as possible, until there // is no more input data or no more space in the output buffer (see below // about the flush parameter). // // Before the call of inflate(), the application should ensure that at least // one of the actions is possible, by providing more input and/or consuming // more output, and updating the next_* and avail_* values accordingly. // The application can consume the uncompressed output when it wants, for // example when the output buffer is full (avail_out == 0), or after each // call of inflate(). If inflate returns Z_OK and with zero avail_out, it // must be called again after making room in the output buffer because there // might be more output pending. // // If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much // output as possible to the output buffer. The flushing behavior of inflate is // not specified for values of the flush parameter other than Z_SYNC_FLUSH // and Z_FINISH, but the current implementation actually flushes as much output // as possible anyway. // // inflate() should normally be called until it returns Z_STREAM_END or an // error. However if all decompression is to be performed in a single step // (a single call of inflate), the parameter flush should be set to // Z_FINISH. In this case all pending input is processed and all pending // output is flushed; avail_out must be large enough to hold all the // uncompressed data. (The size of the uncompressed data may have been saved // by the compressor for this purpose.) The next operation on this stream must // be inflateEnd to deallocate the decompression state. The use of Z_FINISH // is never required, but can be used to inform inflate that a faster routine // may be used for the single inflate() call. // // If a preset dictionary is needed at this point (see inflateSetDictionary // below), inflate sets strm-adler to the adler32 checksum of the // dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise // it sets strm->adler to the adler32 checksum of all output produced // so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or // an error code as described below. At the end of the stream, inflate() // checks that its computed adler32 checksum is equal to that saved by the // compressor and returns Z_STREAM_END only if the checksum is correct. // // inflate() returns Z_OK if some progress has been made (more input processed // or more output produced), Z_STREAM_END if the end of the compressed data has // been reached and all uncompressed output has been produced, Z_NEED_DICT if a // preset dictionary is needed at this point, Z_DATA_ERROR if the input data was // corrupted (input stream not conforming to the zlib format or incorrect // adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent // (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if no progress is possible or if there was not // enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR // case, the application may then call inflateSync to look for a good // compression block. // int inflateEnd (z_streamp strm); // // All dynamically allocated data structures for this stream are freed. // This function discards any unprocessed input and does not flush any // pending output. // // inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state // was inconsistent. In the error case, msg may be set but then points to a // static string (which must not be deallocated). // Advanced functions // The following functions are needed only in some special applications. int inflateSetDictionary (z_streamp strm, const Byte *dictionary, uInt dictLength); // // Initializes the decompression dictionary from the given uncompressed byte // sequence. This function must be called immediately after a call of inflate // if this call returned Z_NEED_DICT. The dictionary chosen by the compressor // can be determined from the Adler32 value returned by this call of // inflate. The compressor and decompressor must use exactly the same // dictionary. // // inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a // parameter is invalid (such as NULL dictionary) or the stream state is // inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the // expected one (incorrect Adler32 value). inflateSetDictionary does not // perform any decompression: this will be done by subsequent calls of // inflate(). int inflateSync (z_streamp strm); // // Skips invalid compressed data until a full flush point can be found, or until all // available input is skipped. No output is provided. // // inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR // if no more input was provided, Z_DATA_ERROR if no flush point has been found, // or Z_STREAM_ERROR if the stream structure was inconsistent. In the success // case, the application may save the current current value of total_in which // indicates where valid compressed data was found. In the error case, the // application may repeatedly call inflateSync, providing more input each time, // until success or end of the input data. int inflateReset (z_streamp strm); // This function is equivalent to inflateEnd followed by inflateInit, // but does not free and reallocate all the internal decompression state. // The stream will keep attributes that may have been set by inflateInit2. // // inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent (such as zalloc or state being NULL). // // checksum functions // These functions are not related to compression but are exported // anyway because they might be useful in applications using the // compression library. uLong adler32 (uLong adler, const Byte *buf, uInt len); // Update a running Adler-32 checksum with the bytes buf[0..len-1] and // return the updated checksum. If buf is NULL, this function returns // the required initial value for the checksum. // An Adler-32 checksum is almost as reliable as a CRC32 but can be computed // much faster. Usage example: // // uLong adler = adler32(0L, Z_NULL, 0); // // while (read_buffer(buffer, length) != EOF) { // adler = adler32(adler, buffer, length); // } // if (adler != original_adler) error(); uLong ucrc32 (uLong crc, const Byte *buf, uInt len); // Update a running crc with the bytes buf[0..len-1] and return the updated // crc. If buf is NULL, this function returns the required initial value // for the crc. Pre- and post-conditioning (one's complement) is performed // within this function so it shouldn't be done by the application. // Usage example: // // uLong crc = crc32(0L, Z_NULL, 0); // // while (read_buffer(buffer, length) != EOF) { // crc = crc32(crc, buffer, length); // } // if (crc != original_crc) error(); const char *zError (int err); int inflateSyncPoint (z_streamp z); const uLong *get_crc_table (void); typedef unsigned char uch; typedef uch uchf; typedef unsigned short ush; typedef ush ushf; typedef unsigned long ulg; const char * const z_errmsg[10] = { // indexed by 2-zlib_error "need dictionary", // Z_NEED_DICT 2 "stream end", // Z_STREAM_END 1 "", // Z_OK 0 "file error", // Z_ERRNO (-1) "stream error", // Z_STREAM_ERROR (-2) "data error", // Z_DATA_ERROR (-3) "insufficient memory", // Z_MEM_ERROR (-4) "buffer error", // Z_BUF_ERROR (-5) "incompatible version",// Z_VERSION_ERROR (-6) ""}; #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = (char*)ERR_MSG(err), (err)) // To be used only when the state is known to be valid // common constants #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 // The three kinds of block type #define MIN_MATCH 3 #define MAX_MATCH 258 // The minimum and maximum match lengths #define PRESET_DICT 0x20 // preset dictionary flag in zlib header // target dependencies #define OS_CODE 0x0b // Window 95 & Windows NT // functions #define zmemzero(dest, len) memset(dest, 0, len) // Diagnostic functions #define LuAssert(cond,msg) #define LuTrace(x) #define LuTracev(x) #define LuTracevv(x) #define LuTracec(c,x) #define LuTracecv(c,x) typedef uLong (*check_func) (uLong check, const Byte *buf, uInt len); voidpf zcalloc (voidpf opaque, unsigned items, unsigned size); void zcfree (voidpf opaque, voidpf ptr); #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) //void ZFREE(z_streamp strm,voidpf addr) //{ *((strm)->zfree))((strm)->opaque, addr); //} #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} // Huffman code lookup table entry--this entry is four bytes for machines // that have 16-bit pointers (e.g. PC's in the small or medium model). typedef struct inflate_huft_s inflate_huft; struct inflate_huft_s { union { struct { Byte Exop; // number of extra bits or operation Byte Bits; // number of bits in this code or subcode } what; uInt pad; // pad structure to a power of 2 (4 bytes for } word; // 16-bit, 8 bytes for 32-bit int's) uInt base; // literal, length base, distance base, or table offset }; // Maximum size of dynamic tree. The maximum found in a long but non- // exhaustive search was 1004 huft structures (850 for length/literals // and 154 for distances, the latter actually the result of an // exhaustive search). The actual maximum is not known, but the // value below is more than safe. #define MANY 1440 int inflate_trees_bits ( uInt *, // 19 code lengths uInt *, // bits tree desired/actual depth inflate_huft * *, // bits tree result inflate_huft *, // space for trees z_streamp); // for messages int inflate_trees_dynamic ( uInt, // number of literal/length codes uInt, // number of distance codes uInt *, // that many (total) code lengths uInt *, // literal desired/actual bit depth uInt *, // distance desired/actual bit depth inflate_huft * *, // literal/length tree result inflate_huft * *, // distance tree result inflate_huft *, // space for trees z_streamp); // for messages int inflate_trees_fixed ( uInt *, // literal desired/actual bit depth uInt *, // distance desired/actual bit depth const inflate_huft * *, // literal/length tree result const inflate_huft * *, // distance tree result z_streamp); // for memory allocation struct inflate_blocks_state; typedef struct inflate_blocks_state inflate_blocks_statef; inflate_blocks_statef * inflate_blocks_new ( z_streamp z, check_func c, // check function uInt w); // window size int inflate_blocks ( inflate_blocks_statef *, z_streamp , int); // initial return code void inflate_blocks_reset ( inflate_blocks_statef *, z_streamp , uLong *); // check value on output int inflate_blocks_free ( inflate_blocks_statef *, z_streamp); void inflate_set_dictionary ( inflate_blocks_statef *s, const Byte *d, // dictionary uInt n); // dictionary length int inflate_blocks_sync_point ( inflate_blocks_statef *s); struct inflate_codes_state; typedef struct inflate_codes_state inflate_codes_statef; inflate_codes_statef *inflate_codes_new ( uInt, uInt, const inflate_huft *, const inflate_huft *, z_streamp ); int inflate_codes ( inflate_blocks_statef *, z_streamp , int); void inflate_codes_free ( inflate_codes_statef *, z_streamp ); typedef enum { IBM_TYPE, // get type bits (3, including end bit) IBM_LENS, // get lengths for stored IBM_STORED, // processing stored block IBM_TABLE, // get table lengths IBM_BTREE, // get bit lengths tree for a dynamic block IBM_DTREE, // get length, distance trees for a dynamic block IBM_CODES, // processing fixed or dynamic block IBM_DRY, // output remaining window bytes IBM_DONE, // finished last block, done IBM_BAD} // got a data error--stuck here inflate_block_mode; // inflate blocks semi-private state struct inflate_blocks_state { // mode inflate_block_mode mode; // current inflate_block mode // mode dependent information union { uInt left; // if STORED, bytes left to copy struct { uInt table; // table lengths (14 bits) uInt index; // index into blens (or border) uInt *blens; // bit lengths of codes uInt bb; // bit length tree depth inflate_huft *tb; // bit length decoding tree } trees; // if DTREE, decoding info for trees struct { inflate_codes_statef *codes; } decode; // if CODES, current state } sub; // submode uInt last; // true if this block is the last block // mode independent information uInt bitk; // bits in bit buffer uLong bitb; // bit buffer inflate_huft *hufts; // single malloc for tree space Byte *window; // sliding window Byte *end; // one byte after sliding window Byte *read; // window read pointer Byte *write; // window write pointer check_func checkfn; // check function uLong check; // check on output }; // defines for inflate input/output // update pointers and return #define UPDBITS {s->bitb=b;s->bitk=k;} #define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} #define UPDOUT {s->write=q;} #define UPDATE {UPDBITS UPDIN UPDOUT} #define LEAVE {UPDATE return inflate_flush(s,z,r);} // get bytes and bits #define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} #define NEEDBYTE {if(n)r=Z_OK;else LEAVE} #define NEXTBYTE (n--,*p++) #define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} // output bytes #define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) #define LOADOUT {q=s->write;m=(uInt)WAVAIL;} #define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} #define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} #define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} #define OUTBYTE(a) {*q++=(Byte)(a);m--;} // load local pointers #define LOAD {LOADIN LOADOUT} // masks for lower bits (size given to avoid silly warnings with Visual C++) // And'ing with mask[n] masks the lower n bits const uInt inflate_mask[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; // copy as much as possible from the sliding window to the output area int inflate_flush (inflate_blocks_statef *, z_streamp, int); int inflate_fast (uInt, uInt, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp ); const uInt fixed_bl = 9; const uInt fixed_bd = 5; const inflate_huft fixed_tl[] = { {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} }; const inflate_huft fixed_td[] = { {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} }; // copy as much as possible from the sliding window to the output area int inflate_flush(inflate_blocks_statef *s,z_streamp z,int r) { uInt n; Byte *p; Byte *q; // local copies of source and destination pointers p = z->next_out; q = s->read; // compute number of bytes to copy as far as end of window n = (uInt)((q <= s->write ? s->write : s->end) - q); if (n > z->avail_out) n = z->avail_out; if (n && r == Z_BUF_ERROR) r = Z_OK; // update counters z->avail_out -= n; z->total_out += n; // update check information if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); // copy as far as end of window if (n!=0) // check for n!=0 to avoid waking up CodeGuard { memcpy(p, q, n); p += n; q += n; } // see if more to copy at beginning of window if (q == s->end) { // wrap pointers q = s->window; if (s->write == s->end) s->write = s->window; // compute bytes to copy n = (uInt)(s->write - q); if (n > z->avail_out) n = z->avail_out; if (n && r == Z_BUF_ERROR) r = Z_OK; // update counters z->avail_out -= n; z->total_out += n; // update check information if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); // copy if (n!=0) {memcpy(p,q,n); p+=n; q+=n;} } // update pointers z->next_out = p; s->read = q; // done return r; } // simplify the use of the inflate_huft type with some defines #define exop word.what.Exop #define bits word.what.Bits typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing START, // x: set up for LEN LEN, // i: get length/literal/eob next LENEXT, // i: getting length extra (have base) DIST, // i: get distance next DISTEXT, // i: getting distance extra COPY, // o: copying bytes in window, waiting for space LIT, // o: got literal, waiting for output space WASH, // o: got eob, possibly still output waiting END, // x: got eob and all data flushed BADCODE} // x: got error inflate_codes_mode; // inflate codes private state struct inflate_codes_state { // mode inflate_codes_mode mode; // current inflate_codes mode // mode dependent information uInt len; union { struct { const inflate_huft *tree; // pointer into tree uInt need; // bits needed } code; // if LEN or DIST, where in tree uInt lit; // if LIT, literal struct { uInt get; // bits to get for extra uInt dist; // distance back to copy from } copy; // if EXT or COPY, where and how much } sub; // submode // mode independent information Byte lbits; // ltree bits decoded per branch Byte dbits; // dtree bits decoder per branch const inflate_huft *ltree; // literal/length/eob tree const inflate_huft *dtree; // distance tree }; inflate_codes_statef *inflate_codes_new( uInt bl, uInt bd, const inflate_huft *tl, const inflate_huft *td, // need separate declaration for Borland C++ z_streamp z) { inflate_codes_statef *c; if ((c = (inflate_codes_statef *) ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) { c->mode = START; c->lbits = (Byte)bl; c->dbits = (Byte)bd; c->ltree = tl; c->dtree = td; LuTracev((stderr, "inflate: codes new\n")); } return c; } int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) { uInt j; // temporary storage const inflate_huft *t; // temporary pointer uInt e; // extra bits or operation uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer Byte *f; // pointer to copy strings from inflate_codes_statef *c = s->sub.decode.codes; // codes state // copy input/output information to locals (UPDATE macro restores) LOAD // process input and output based on current state for(;;) switch (c->mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN #ifndef SLOW if (m >= 258 && n >= 10) { UPDATE r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); LOAD if (r != Z_OK) { c->mode = r == Z_STREAM_END ? WASH : BADCODE; break; } } #endif // !SLOW c->sub.code.need = c->lbits; c->sub.code.tree = c->ltree; c->mode = LEN; case LEN: // i: get length/literal/eob next j = c->sub.code.need; NEEDBITS(j) t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e == 0) // literal { c->sub.lit = t->base; LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", t->base)); c->mode = LIT; break; } if (e & 16) // length { c->sub.copy.get = e & 15; c->len = t->base; c->mode = LENEXT; break; } if ((e & 64) == 0) // next table { c->sub.code.need = e; c->sub.code.tree = t + t->base; break; } if (e & 32) // end of block { LuTracevv((stderr, "inflate: end of block\n")); c->mode = WASH; break; } c->mode = BADCODE; // invalid code z->msg = (char*)"invalid literal/length code"; r = Z_DATA_ERROR; LEAVE case LENEXT: // i: getting length extra (have base) j = c->sub.copy.get; NEEDBITS(j) c->len += (uInt)b & inflate_mask[j]; DUMPBITS(j) c->sub.code.need = c->dbits; c->sub.code.tree = c->dtree; LuTracevv((stderr, "inflate: length %u\n", c->len)); c->mode = DIST; case DIST: // i: get distance next j = c->sub.code.need; NEEDBITS(j) t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e & 16) // distance { c->sub.copy.get = e & 15; c->sub.copy.dist = t->base; c->mode = DISTEXT; break; } if ((e & 64) == 0) // next table { c->sub.code.need = e; c->sub.code.tree = t + t->base; break; } c->mode = BADCODE; // invalid code z->msg = (char*)"invalid distance code"; r = Z_DATA_ERROR; LEAVE case DISTEXT: // i: getting distance extra j = c->sub.copy.get; NEEDBITS(j) c->sub.copy.dist += (uInt)b & inflate_mask[j]; DUMPBITS(j) LuTracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: // o: copying bytes in window, waiting for space f = q - c->sub.copy.dist; while (f < s->window) // modulo window size-"while" instead f += s->end - s->window; // of "if" handles invalid distances while (c->len) { NEEDOUT OUTBYTE(*f++) if (f == s->end) f = s->window; c->len--; } c->mode = START; break; case LIT: // o: got literal, waiting for output space NEEDOUT OUTBYTE(c->sub.lit) c->mode = START; break; case WASH: // o: got eob, possibly more output if (k > 7) // return unused byte, if any { //Assert(k < 16, "inflate_codes grabbed too many bytes") k -= 8; n++; p--; // can always return one } FLUSH if (s->read != s->write) LEAVE c->mode = END; case END: r = Z_STREAM_END; LEAVE case BADCODE: // x: got error r = Z_DATA_ERROR; LEAVE default: r = Z_STREAM_ERROR; LEAVE } } void inflate_codes_free(inflate_codes_statef *c,z_streamp z) { ZFREE(z, c); LuTracev((stderr, "inflate: codes free\n")); } // infblock.c -- interpret and process block types to last block // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h //struct inflate_codes_state {int dummy;}; // for buggy compilers // Table for deflate from PKZIP's appnote.txt. const uInt border[] = { // Order of the bit length code lengths 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; // // Notes beyond the 1.93a appnote.txt: // // 1. Distance pointers never point before the beginning of the output stream. // 2. Distance pointers can point back across blocks, up to 32k away. // 3. There is an implied maximum of 7 bits for the bit length table and // 15 bits for the actual data. // 4. If only one code exists, then it is encoded using one bit. (Zero // would be more efficient, but perhaps a little confusing.) If two // codes exist, they are coded using one bit each (0 and 1). // 5. There is no way of sending zero distance codes--a dummy must be // sent if there are none. (History: a pre 2.0 version of PKZIP would // store blocks with no distance codes, but this was discovered to be // too harsh a criterion.) Valid only for 1.93a. 2.04c does allow // zero distance codes, which is sent as one code of zero bits in // length. // 6. There are up to 286 literal/length codes. Code 256 represents the // end-of-block. Note however that the static length tree defines // 288 codes just to fill out the Huffman codes. Codes 286 and 287 // cannot be used though, since there is no length base or extra bits // defined for them. Similarly, there are up to 30 distance codes. // However, static trees define 32 codes (all 5 bits) to fill out the // Huffman codes, but the last two had better not show up in the data. // 7. Unzip can check dynamic Huffman blocks for complete code sets. // The exception is that a single code would not be complete (see #4). // 8. The five bits following the block type is really the number of // literal codes sent minus 257. // 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits // (1+6+6). Therefore, to output three times the length, you output // three codes (1+1+1), whereas to output four times the same length, // you only need two codes (1+3). Hmm. //10. In the tree reconstruction algorithm, Code = Code + Increment // only if BitLength(i) is not zero. (Pretty obvious.) //11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) //12. Note: length code 284 can represent 227-258, but length code 285 // really is 258. The last length deserves its own, short code // since it gets used a lot in very redundant files. The length // 258 is special since 258 - 3 (the min match length) is 255. //13. The literal/length and distance code bit lengths are read as a // single stream of lengths. It is possible (and advantageous) for // a repeat code (16, 17, or 18) to go across the boundary between // the two sets of lengths. void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) { if (c != Z_NULL) *c = s->check; if (s->mode == IBM_BTREE || s->mode == IBM_DTREE) ZFREE(z, s->sub.trees.blens); if (s->mode == IBM_CODES) inflate_codes_free(s->sub.decode.codes, z); s->mode = IBM_TYPE; s->bitk = 0; s->bitb = 0; s->read = s->write = s->window; if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); LuTracev((stderr, "inflate: blocks reset\n")); } inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) { inflate_blocks_statef *s; if ((s = (inflate_blocks_statef *)ZALLOC (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) return s; if ((s->hufts = (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) { ZFREE(z, s); return Z_NULL; } if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) { ZFREE(z, s->hufts); ZFREE(z, s); return Z_NULL; } s->end = s->window + w; s->checkfn = c; s->mode = IBM_TYPE; LuTracev((stderr, "inflate: blocks allocated\n")); inflate_blocks_reset(s, z, Z_NULL); return s; } int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) { uInt t; // temporary storage uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer // copy input/output information to locals (UPDATE macro restores) LOAD // process input based on current state for(;;) switch (s->mode) { case IBM_TYPE: NEEDBITS(3) t = (uInt)b & 7; s->last = t & 1; switch (t >> 1) { case 0: // stored LuTracev((stderr, "inflate: stored block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) t = k & 7; // go to byte boundary DUMPBITS(t) s->mode = IBM_LENS; // get length of stored block break; case 1: // fixed LuTracev((stderr, "inflate: fixed codes block%s\n", s->last ? " (last)" : "")); { uInt bl, bd; const inflate_huft *tl, *td; inflate_trees_fixed(&bl, &bd, &tl, &td, z); s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); if (s->sub.decode.codes == Z_NULL) { r = Z_MEM_ERROR; LEAVE } } DUMPBITS(3) s->mode = IBM_CODES; break; case 2: // dynamic LuTracev((stderr, "inflate: dynamic codes block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) s->mode = IBM_TABLE; break; case 3: // illegal DUMPBITS(3) s->mode = IBM_BAD; z->msg = (char*)"invalid block type"; r = Z_DATA_ERROR; LEAVE } break; case IBM_LENS: NEEDBITS(32) if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) { s->mode = IBM_BAD; z->msg = (char*)"invalid stored block lengths"; r = Z_DATA_ERROR; LEAVE } s->sub.left = (uInt)b & 0xffff; b = k = 0; // dump bits LuTracev((stderr, "inflate: stored length %u\n", s->sub.left)); s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE); break; case IBM_STORED: if (n == 0) LEAVE NEEDOUT t = s->sub.left; if (t > n) t = n; if (t > m) t = m; memcpy(q, p, t); p += t; n -= t; q += t; m -= t; if ((s->sub.left -= t) != 0) break; LuTracev((stderr, "inflate: stored end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : (s->end - s->read) + (q - s->window)))); s->mode = s->last ? IBM_DRY : IBM_TYPE; break; case IBM_TABLE: NEEDBITS(14) s->sub.trees.table = t = (uInt)b & 0x3fff; // remove this section to workaround bug in pkzip if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) { s->mode = IBM_BAD; z->msg = (char*)"too many length or distance symbols"; r = Z_DATA_ERROR; LEAVE } // end remove t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) { r = Z_MEM_ERROR; LEAVE } DUMPBITS(14) s->sub.trees.index = 0; LuTracev((stderr, "inflate: table sizes ok\n")); s->mode = IBM_BTREE; case IBM_BTREE: while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) { NEEDBITS(3) s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; DUMPBITS(3) } while (s->sub.trees.index < 19) s->sub.trees.blens[border[s->sub.trees.index++]] = 0; s->sub.trees.bb = 7; t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, &s->sub.trees.tb, s->hufts, z); if (t != Z_OK) { r = t; if (r == Z_DATA_ERROR) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; } LEAVE } s->sub.trees.index = 0; LuTracev((stderr, "inflate: bits tree ok\n")); s->mode = IBM_DTREE; case IBM_DTREE: while (t = s->sub.trees.table, s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) { inflate_huft *h; uInt i, j, c; t = s->sub.trees.bb; NEEDBITS(t) h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); t = h->bits; c = h->base; if (c < 16) { DUMPBITS(t) s->sub.trees.blens[s->sub.trees.index++] = c; } else // c == 16..18 { i = c == 18 ? 7 : c - 14; j = c == 18 ? 11 : 3; NEEDBITS(t + i) DUMPBITS(t) j += (uInt)b & inflate_mask[i]; DUMPBITS(i) i = s->sub.trees.index; t = s->sub.trees.table; if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; z->msg = (char*)"invalid bit length repeat"; r = Z_DATA_ERROR; LEAVE } c = c == 16 ? s->sub.trees.blens[i - 1] : 0; do { s->sub.trees.blens[i++] = c; } while (--j); s->sub.trees.index = i; } } s->sub.trees.tb = Z_NULL; { uInt bl, bd; inflate_huft *tl, *td; inflate_codes_statef *c; bl = 9; // must be <= 9 for lookahead assumptions bd = 6; // must be <= 9 for lookahead assumptions t = s->sub.trees.table; t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), s->sub.trees.blens, &bl, &bd, &tl, &td, s->hufts, z); if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; } r = t; LEAVE } LuTracev((stderr, "inflate: trees ok\n")); if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { r = Z_MEM_ERROR; LEAVE } s->sub.decode.codes = c; } ZFREE(z, s->sub.trees.blens); s->mode = IBM_CODES; case IBM_CODES: UPDATE if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) return inflate_flush(s, z, r); r = Z_OK; inflate_codes_free(s->sub.decode.codes, z); LOAD LuTracev((stderr, "inflate: codes end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : (s->end - s->read) + (q - s->window)))); if (!s->last) { s->mode = IBM_TYPE; break; } s->mode = IBM_DRY; case IBM_DRY: FLUSH if (s->read != s->write) LEAVE s->mode = IBM_DONE; case IBM_DONE: r = Z_STREAM_END; LEAVE case IBM_BAD: r = Z_DATA_ERROR; LEAVE default: r = Z_STREAM_ERROR; LEAVE } } int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) { inflate_blocks_reset(s, z, Z_NULL); ZFREE(z, s->window); ZFREE(z, s->hufts); ZFREE(z, s); LuTracev((stderr, "inflate: blocks freed\n")); return Z_OK; } // inftrees.c -- generate Huffman trees for efficient decoding // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // extern const char inflate_copyright[] = " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; // If you use the zlib library in a product, an acknowledgment is welcome // in the documentation of your product. If for some reason you cannot // include such an acknowledgment, I would appreciate that you keep this // copyright string in the executable of your product. int huft_build ( uInt *, // code lengths in bits uInt, // number of codes uInt, // number of "simple" codes const uInt *, // list of base values for non-simple codes const uInt *, // list of extra bits for non-simple codes inflate_huft **,// result: starting table uInt *, // maximum lookup bits (returns actual) inflate_huft *, // space for trees uInt *, // hufts used in space uInt * ); // space for values // Tables for deflate from PKZIP's appnote.txt. const uInt cplens[31] = { // Copy lengths for literal codes 257..285 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; // see note #13 above about 258 const uInt cplext[31] = { // Extra bits for literal codes 257..285 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid const uInt cpdist[30] = { // Copy offsets for distance codes 0..29 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; const uInt cpdext[30] = { // Extra bits for distance codes 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; // // Huffman code decoding is performed using a multi-level table lookup. // The fastest way to decode is to simply build a lookup table whose // size is determined by the longest code. However, the time it takes // to build this table can also be a factor if the data being decoded // is not very long. The most common codes are necessarily the // shortest codes, so those codes dominate the decoding time, and hence // the speed. The idea is you can have a shorter table that decodes the // shorter, more probable codes, and then point to subsidiary tables for // the longer codes. The time it costs to decode the longer codes is // then traded against the time it takes to make longer tables. // // This results of this trade are in the variables lbits and dbits // below. lbits is the number of bits the first level table for literal/ // length codes can decode in one step, and dbits is the same thing for // the distance codes. Subsequent tables are also less than or equal to // those sizes. These values may be adjusted either when all of the // codes are shorter than that, in which case the longest code length in // bits is used, or when the shortest code is *longer* than the requested // table size, in which case the length of the shortest code in bits is // used. // // There are two different values for the two tables, since they code a // different number of possibilities each. The literal/length table // codes 286 possible values, or in a flat code, a little over eight // bits. The distance table codes 30 possible values, or a little less // than five bits, flat. The optimum values for speed end up being // about one bit more than those, so lbits is 8+1 and dbits is 5+1. // The optimum values may differ though from machine to machine, and // possibly even between compilers. Your mileage may vary. // // If BMAX needs to be larger than 16, then h and x[] should be uLong. #define BMAX 15 // maximum bit length of any code int huft_build( uInt *b, // code lengths in bits (all assumed <= BMAX) uInt n, // number of codes (assumed <= 288) uInt s, // number of simple-valued codes (0..s-1) const uInt *d, // list of base values for non-simple codes const uInt *e, // list of extra bits for non-simple codes inflate_huft * *t, // result: starting table uInt *m, // maximum lookup bits, returns actual inflate_huft *hp, // space for trees uInt *hn, // hufts used in space uInt *v) // working area: values in order of bit length // Given a list of code lengths and a maximum table size, make a set of // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR // if the given code set is incomplete (the tables are still built in this // case), or Z_DATA_ERROR if the input is invalid. { uInt a; // counter for codes of length k uInt c[BMAX+1]; // bit length count table uInt f; // i repeats in table every f entries int g; // maximum code length int h; // table level register uInt i; // counter, current code register uInt j; // counter register int k; // number of bits in current code int l; // bits per table (returned in m) uInt mask; // (1 << w) - 1, to avoid cc -O bug on HP register uInt *p; // pointer into c[], b[], or v[] inflate_huft *q; // points to current table struct inflate_huft_s r; // table entry for structure assignment inflate_huft *u[BMAX]; // table stack register int w; // bits before this table == (l * h) uInt x[BMAX+1]; // bit offsets, then code stack uInt *xp; // pointer into x int y; // number of dummy codes added uInt z; // number of entries in current table // provide a default value r.base = 0; // Generate counts for each bit length p = c; #define C0 *p++ = 0; #define C2 C0 C0 C0 C0 #define C4 C2 C2 C2 C2 C4; // clear c[]--assume BMAX+1 is 16 p = b; i = n; do { c[*p++]++; // assume all entries <= BMAX } while (--i); if (c[0] == n) // null input--all zero length codes { *t = (inflate_huft *)Z_NULL; *m = 0; return Z_OK; } // Find minimum and maximum length, bound *m by those l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; // minimum code length if ((uInt)l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; // maximum code length if ((uInt)l > i) l = i; *m = l; // Adjust last length count to fill out codes, if needed for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return Z_DATA_ERROR; if ((y -= c[i]) < 0) return Z_DATA_ERROR; c[i] += y; // Generate starting offsets into the value table for each length x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { // note that i == g from above *xp++ = (j += *p++); } // Make a table of values in order of bit lengths p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); n = x[g]; // set n to length of v // Generate the Huffman codes and for each, make the table entries x[0] = i = 0; // first Huffman code is zero p = v; // grab values in bit order h = -1; // no tables yet--level -1 w = -l; // bits decoded == (l * h) u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy q = (inflate_huft *)Z_NULL; // ditto z = 0; // ditto // go through the bit lengths (k already is bits in shortest code) for (; k <= g; k++) { a = c[k]; while (a--) { // here i is the Huffman code of length k bits for value *p // make tables up to required level while (k > w + l) { h++; w += l; // previous table always l bits // compute minimum size table less than or equal to l bits z = g - w; z = z > (uInt)l ? l : z; // table size upper limit if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table { // too few codes for k-w bit table f -= a + 1; // deduct codes from patterns left xp = c + k; if (j < z) while (++j < z) // try smaller tables up to z bits { if ((f <<= 1) <= *++xp) break; // enough codes to use up j bits f -= *xp; // else deduct codes from patterns } } z = 1 << j; // table entries for j-bit table // allocate new table if (*hn + z > MANY) // (note: doesn't matter for fixed) return Z_DATA_ERROR; // overflow of MANY u[h] = q = hp + *hn; *hn += z; // connect to last table, if there is one if (h) { x[h] = i; // save pattern for backing up r.bits = (Byte)l; // bits to dump before this table r.exop = (Byte)j; // bits in this table j = i >> (w - l); r.base = (uInt)(q - u[h-1] - j); // offset to this table u[h-1][j] = r; // connect to last table } else *t = q; // first table is returned result } // set up table entry in r r.bits = (Byte)(k - w); if (p >= v + n) r.exop = 128 + 64; // out of values--invalid code else if (*p < s) { r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block r.base = *p++; // simple code is just the value } else { r.exop = (Byte)(e[*p - s] + 16 + 64);// non-simple--look up in lists r.base = d[*p++ - s]; } // fill code-like entries with r f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; // backwards increment the k-bit code i for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; // backup over finished tables mask = (1 << w) - 1; // needed on HP, cc -O bug while ((i & mask) != x[h]) { h--; // don't need to update q w -= l; mask = (1 << w) - 1; } } } // Return Z_BUF_ERROR if we were given an incomplete table return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; } int inflate_trees_bits( uInt *c, // 19 code lengths uInt *bb, // bits tree desired/actual depth inflate_huft * *tb, // bits tree result inflate_huft *hp, // space for trees z_streamp z) // for messages { int r; uInt hn = 0; // hufts used in space uInt *v; // work area for huft_build if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) return Z_MEM_ERROR; r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, tb, bb, hp, &hn, v); if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed dynamic bit lengths tree"; else if (r == Z_BUF_ERROR || *bb == 0) { z->msg = (char*)"incomplete dynamic bit lengths tree"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } int inflate_trees_dynamic( uInt nl, // number of literal/length codes uInt nd, // number of distance codes uInt *c, // that many (total) code lengths uInt *bl, // literal desired/actual bit depth uInt *bd, // distance desired/actual bit depth inflate_huft * *tl, // literal/length tree result inflate_huft * *td, // distance tree result inflate_huft *hp, // space for trees z_streamp z) // for messages { int r; uInt hn = 0; // hufts used in space uInt *v; // work area for huft_build // allocate work area if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) return Z_MEM_ERROR; // build literal/length tree r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); if (r != Z_OK || *bl == 0) { if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed literal/length tree"; else if (r != Z_MEM_ERROR) { z->msg = (char*)"incomplete literal/length tree"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } // build distance tree r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); if (r != Z_OK || (*bd == 0 && nl > 257)) { if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed distance tree"; else if (r == Z_BUF_ERROR) { z->msg = (char*)"incomplete distance tree"; r = Z_DATA_ERROR; } else if (r != Z_MEM_ERROR) { z->msg = (char*)"empty distance tree with lengths"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } // done ZFREE(z, v); return Z_OK; } int inflate_trees_fixed( uInt *bl, // literal desired/actual bit depth uInt *bd, // distance desired/actual bit depth const inflate_huft * * tl, // literal/length tree result const inflate_huft * *td, // distance tree result z_streamp ) // for memory allocation { *bl = fixed_bl; *bd = fixed_bd; *tl = fixed_tl; *td = fixed_td; return Z_OK; } // inffast.c -- process literals and length/distance pairs fast // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // //struct inflate_codes_state {int dummy;}; // for buggy compilers // macros for bit input with no checking and for returning unused bytes #define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} // Called with number of bytes left to write in window at least 258 // (the maximum string length) and number of input bytes available // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. int inflate_fast( uInt bl, uInt bd, const inflate_huft *tl, const inflate_huft *td, // need separate declaration for Borland C++ inflate_blocks_statef *s, z_streamp z) { const inflate_huft *t; // temporary pointer uInt e; // extra bits or operation uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer uInt ml; // mask for literal/length tree uInt md; // mask for distance tree uInt c; // bytes to copy uInt d; // distance back to copy from Byte *r; // copy source pointer // load input, output, bit values LOAD // initialize masks ml = inflate_mask[bl]; md = inflate_mask[bd]; // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code GRABBITS(20) // max bits for literal/length code if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) { DUMPBITS(t->bits) LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: * literal '%c'\n" : "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; continue; } for (;;) { DUMPBITS(t->bits) if (e & 16) { // get extra bits for length e &= 15; c = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) LuTracevv((stderr, "inflate: * length %u\n", c)); // decode distance base of block to copy GRABBITS(15); // max bits for distance code e = (t = td + ((uInt)b & md))->exop; for (;;) { DUMPBITS(t->bits) if (e & 16) { // get extra bits to add to distance base e &= 15; GRABBITS(e) // get extra bits (up to 13) d = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) LuTracevv((stderr, "inflate: * distance %u\n", d)); // do the copy m -= c; r = q - d; if (r < s->window) // wrap if needed { do { r += s->end - s->window; // force pointer in window } while (r < s->window); // covers invalid distances e = (uInt) (s->end - r); if (c > e) { c -= e; // wrapped copy do { *q++ = *r++; } while (--e); r = s->window; do { *q++ = *r++; } while (--c); } else // normal copy { *q++ = *r++; c--; *q++ = *r++; c--; do { *q++ = *r++; } while (--c); } } else /* normal copy */ { *q++ = *r++; c--; *q++ = *r++; c--; do { *q++ = *r++; } while (--c); } break; } else if ((e & 64) == 0) { t += t->base; e = (t += ((uInt)b & inflate_mask[e]))->exop; } else { z->msg = (char*)"invalid distance code"; UNGRAB UPDATE return Z_DATA_ERROR; } }; break; } if ((e & 64) == 0) { t += t->base; if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: * literal '%c'\n" : "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; break; } } else if (e & 32) { LuTracevv((stderr, "inflate: * end of block\n")); UNGRAB UPDATE return Z_STREAM_END; } else { z->msg = (char*)"invalid literal/length code"; UNGRAB UPDATE return Z_DATA_ERROR; } }; } while (m >= 258 && n >= 10); // not enough input or output--restore pointers and return UNGRAB UPDATE return Z_OK; } // crc32.c -- compute the CRC-32 of a data stream // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ // Table of CRC-32's of all single-byte values (made by make_crc_table) const uLong crc_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; const uLong * get_crc_table() { return (const uLong *)crc_table; } #define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define CRC_DO2(buf) CRC_DO1(buf); CRC_DO1(buf); #define CRC_DO4(buf) CRC_DO2(buf); CRC_DO2(buf); #define CRC_DO8(buf) CRC_DO4(buf); CRC_DO4(buf); uLong ucrc32(uLong crc, const Byte *buf, uInt len) { if (buf == Z_NULL) return 0L; crc = crc ^ 0xffffffffL; while (len >= 8) {CRC_DO8(buf); len -= 8;} if (len) do {CRC_DO1(buf);} while (--len); return crc ^ 0xffffffffL; } // ============================================================= // some decryption routines #define CRC32(c, b) (crc_table[((int)(c)^(b))&0xff]^((c)>>8)) void Uupdate_keys(unsigned long *keys, char c) { keys[0] = CRC32(keys[0],c); keys[1] += keys[0] & 0xFF; keys[1] = keys[1]*134775813L +1; keys[2] = CRC32(keys[2], keys[1] >> 24); } char Udecrypt_byte(unsigned long *keys) { unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); } char zdecode(unsigned long *keys, char c) { c^=Udecrypt_byte(keys); Uupdate_keys(keys,c); return c; } // adler32.c -- compute the Adler-32 checksum of a data stream // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ #define BASE 65521L // largest prime smaller than 65536 #define NMAX 5552 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 #define AD_DO1(buf,i) {s1 += buf[i]; s2 += s1;} #define AD_DO2(buf,i) AD_DO1(buf,i); AD_DO1(buf,i+1); #define AD_DO4(buf,i) AD_DO2(buf,i); AD_DO2(buf,i+2); #define AD_DO8(buf,i) AD_DO4(buf,i); AD_DO4(buf,i+4); #define AD_DO16(buf) AD_DO8(buf,0); AD_DO8(buf,8); // ========================================================================= uLong adler32(uLong adler, const Byte *buf, uInt len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; if (buf == Z_NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { AD_DO16(buf); buf += 16; k -= 16; } if (k != 0) do { s1 += *buf++; s2 += s1; } while (--k); s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } // zutil.c -- target dependent utility functions for the compression library // Copyright (C) 1995-1998 Jean-loup Gailly. // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ const char * zlibVersion() { return ZLIB_VERSION; } // exported to allow conversion of error code to string for compress() and // uncompress() const char * zError(int err) { return ERR_MSG(err); } voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) { if (opaque) items += size - size; // make compiler happy return (voidpf)calloc(items, size); } void zcfree (voidpf opaque, voidpf ptr) { zfree(ptr); if (opaque) return; // make compiler happy } // inflate.c -- zlib interface to inflate modules // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h //struct inflate_blocks_state {int dummy;}; // for buggy compilers typedef enum { IM_METHOD, // waiting for method byte IM_FLAG, // waiting for flag byte IM_DICT4, // four dictionary check bytes to go IM_DICT3, // three dictionary check bytes to go IM_DICT2, // two dictionary check bytes to go IM_DICT1, // one dictionary check byte to go IM_DICT0, // waiting for inflateSetDictionary IM_BLOCKS, // decompressing blocks IM_CHECK4, // four check bytes to go IM_CHECK3, // three check bytes to go IM_CHECK2, // two check bytes to go IM_CHECK1, // one check byte to go IM_DONE, // finished check, done IM_BAD} // got an error--stay here inflate_mode; // inflate private state struct internal_state { // mode inflate_mode mode; // current inflate mode // mode dependent information union { uInt method; // if IM_FLAGS, method byte struct { uLong was; // computed check value uLong need; // stream check value } check; // if CHECK, check values to compare uInt marker; // if IM_BAD, inflateSync's marker bytes count } sub; // submode // mode independent information int nowrap; // flag for no wrapper uInt wbits; // log2(window size) (8..15, defaults to 15) inflate_blocks_statef *blocks; // current inflate_blocks state }; int inflateReset(z_streamp z) { if (z == Z_NULL || z->state == Z_NULL) return Z_STREAM_ERROR; z->total_in = z->total_out = 0; z->msg = Z_NULL; z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD; inflate_blocks_reset(z->state->blocks, z, Z_NULL); LuTracev((stderr, "inflate: reset\n")); return Z_OK; } int inflateEnd(z_streamp z) { if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) return Z_STREAM_ERROR; if (z->state->blocks != Z_NULL) inflate_blocks_free(z->state->blocks, z); ZFREE(z, z->state); z->state = Z_NULL; LuTracev((stderr, "inflate: end\n")); return Z_OK; } int inflateInit2(z_streamp z) { const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream); if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; int w = -15; // MAX_WBITS: 32K LZ77 window. // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files created by gzip. // The memory requirements for deflate are (in bytes): // (1 << (windowBits+2)) + (1 << (memLevel+9)) // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) // plus a few kilobytes for small objects. For example, if you want to reduce // the default memory requirements from 256K to 128K, compile with // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" // Of course this will generally degrade compression (there's no free lunch). // // The memory requirements for inflate are (in bytes) 1 << windowBits // that is, 32K for windowBits=15 (default value) plus a few kilobytes // for small objects. // initialize state if (z == Z_NULL) return Z_STREAM_ERROR; z->msg = Z_NULL; if (z->zalloc == Z_NULL) { z->zalloc = zcalloc; z->opaque = (voidpf)0; } if (z->zfree == Z_NULL) z->zfree = zcfree; if ((z->state = (struct internal_state *) ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) return Z_MEM_ERROR; z->state->blocks = Z_NULL; // handle undocumented nowrap option (no zlib header or check) z->state->nowrap = 0; if (w < 0) { w = - w; z->state->nowrap = 1; } // set window size if (w < 8 || w > 15) { inflateEnd(z); return Z_STREAM_ERROR; } z->state->wbits = (uInt)w; // create inflate_blocks state if ((z->state->blocks = inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) == Z_NULL) { inflateEnd(z); return Z_MEM_ERROR; } LuTracev((stderr, "inflate: allocated\n")); // reset state inflateReset(z); return Z_OK; } #define IM_NEEDBYTE {if(z->avail_in==0)return r;r=f;} #define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) int inflate(z_streamp z, int f) { int r; uInt b; if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) return Z_STREAM_ERROR; f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; r = Z_BUF_ERROR; for (;;) switch (z->state->mode) { case IM_METHOD: IM_NEEDBYTE if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) { z->state->mode = IM_BAD; z->msg = (char*)"unknown compression method"; z->state->sub.marker = 5; // can't try inflateSync break; } if ((z->state->sub.method >> 4) + 8 > z->state->wbits) { z->state->mode = IM_BAD; z->msg = (char*)"invalid window size"; z->state->sub.marker = 5; // can't try inflateSync break; } z->state->mode = IM_FLAG; case IM_FLAG: IM_NEEDBYTE b = IM_NEXTBYTE; if (((z->state->sub.method << 8) + b) % 31) { z->state->mode = IM_BAD; z->msg = (char*)"incorrect header check"; z->state->sub.marker = 5; // can't try inflateSync break; } LuTracev((stderr, "inflate: zlib header ok\n")); if (!(b & PRESET_DICT)) { z->state->mode = IM_BLOCKS; break; } z->state->mode = IM_DICT4; case IM_DICT4: IM_NEEDBYTE z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; z->state->mode = IM_DICT3; case IM_DICT3: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; z->state->mode = IM_DICT2; case IM_DICT2: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; z->state->mode = IM_DICT1; case IM_DICT1: IM_NEEDBYTE; z->state->sub.check.need += (uLong)IM_NEXTBYTE; z->adler = z->state->sub.check.need; z->state->mode = IM_DICT0; return Z_NEED_DICT; case IM_DICT0: z->state->mode = IM_BAD; z->msg = (char*)"need dictionary"; z->state->sub.marker = 0; // can try inflateSync return Z_STREAM_ERROR; case IM_BLOCKS: r = inflate_blocks(z->state->blocks, z, r); if (r == Z_DATA_ERROR) { z->state->mode = IM_BAD; z->state->sub.marker = 0; // can try inflateSync break; } if (r == Z_OK) r = f; if (r != Z_STREAM_END) return r; r = f; inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); if (z->state->nowrap) { z->state->mode = IM_DONE; break; } z->state->mode = IM_CHECK4; case IM_CHECK4: IM_NEEDBYTE z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; z->state->mode = IM_CHECK3; case IM_CHECK3: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; z->state->mode = IM_CHECK2; case IM_CHECK2: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; z->state->mode = IM_CHECK1; case IM_CHECK1: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE; if (z->state->sub.check.was != z->state->sub.check.need) { z->state->mode = IM_BAD; z->msg = (char*)"incorrect data check"; z->state->sub.marker = 5; // can't try inflateSync break; } LuTracev((stderr, "inflate: zlib check ok\n")); z->state->mode = IM_DONE; case IM_DONE: return Z_STREAM_END; case IM_BAD: return Z_DATA_ERROR; default: return Z_STREAM_ERROR; } } // unzip.c -- IO on .zip files using zlib // Version 0.15 beta, Mar 19th, 1998, // Read unzip.h for more info #define UNZ_BUFSIZE (16384) #define UNZ_MAXFILENAMEINZIP (256) #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 0.15 Copyright 1998 Gilles Vollant "; // unz_file_info_interntal contain internal info about a file in zipfile typedef struct unz_file_info_internal_s { unz_file_info_internal_s(): offset_curfile(0) {} uLong offset_curfile;// relative offset of local header 4 bytes } unz_file_info_internal; typedef struct { bool is_handle; // either a handle or memory bool canseek; // for handles: HANDLE h; bool herr; unsigned long initial_offset; bool mustclosehandle; // for memory: void *buf; unsigned int len,pos; // if it's a memory block } LUFILE; LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) { if (flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) {*err=ZR_ARGS; return NULL;} // HANDLE h=0; bool canseek=false; *err=ZR_OK; bool mustclosehandle=false; if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) { if (flags==ZIP_HANDLE) { HANDLE hf = (HANDLE)z; h=hf; mustclosehandle=false; #ifdef DuplicateHandle BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS); if (!res) mustclosehandle=true; #endif } else { #ifdef ZIP_STD h=fopen((const char*)z,"rb"); if (h==0) {*err=ZR_NOFILE; return NULL;} #else h=CreateFile((const TCHAR*)z,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (h==INVALID_HANDLE_VALUE) {*err=ZR_NOFILE; return NULL;} #endif mustclosehandle=true; } // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. DWORD res = GetFilePosU(h); canseek = (res!=0xFFFFFFFF); } LUFILE *lf = new LUFILE; if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) { lf->is_handle=true; lf->mustclosehandle=mustclosehandle; lf->canseek=canseek; lf->h=h; lf->herr=false; lf->initial_offset=0; if (canseek) lf->initial_offset = GetFilePosU(h); } else { lf->is_handle=false; lf->canseek=true; lf->mustclosehandle=false; lf->buf=z; lf->len=len; lf->pos=0; lf->initial_offset=0; } *err=ZR_OK; return lf; } int lufclose(LUFILE *stream) { if (stream==NULL) return EOF; #ifdef ZIP_STD if (stream->mustclosehandle) fclose(stream->h); #else if (stream->mustclosehandle) CloseHandle(stream->h); #endif delete stream; return 0; } int luferror(LUFILE *stream) { if (stream->is_handle && stream->herr) return 1; else return 0; } long int luftell(LUFILE *stream) { if (stream->is_handle && stream->canseek) return GetFilePosU(stream->h)-stream->initial_offset; else if (stream->is_handle) return 0; else return stream->pos; } int lufseek(LUFILE *stream, long offset, int whence) { if (stream->is_handle && stream->canseek) { #ifdef ZIP_STD return fseek(stream->h,stream->initial_offset+offset,whence); #else if (whence==SEEK_SET) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN); else if (whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT); else if (whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END); else return 19; // EINVAL return 0; #endif } else if (stream->is_handle) return 29; // ESPIPE else { if (whence==SEEK_SET) stream->pos=offset; else if (whence==SEEK_CUR) stream->pos+=offset; else if (whence==SEEK_END) stream->pos=stream->len+offset; return 0; } } size_t lufread(void *ptr,size_t size,size_t n,LUFILE *stream) { unsigned int toread = (unsigned int)(size*n); if (stream->is_handle) { #ifdef ZIP_STD return fread(ptr,size,n,stream->h); #else DWORD red; BOOL res = ReadFile(stream->h,ptr,toread,&red,NULL); if (!res) stream->herr=true; return red/size; #endif } if (stream->pos+toread > stream->len) toread = stream->len-stream->pos; memcpy(ptr, (char*)stream->buf + stream->pos, toread); DWORD red = toread; stream->pos += red; return red/size; } // file_in_zip_read_info_s contain internal information about a file in zipfile, // when reading and decompress it typedef struct { char *read_buffer; // internal buffer for compressed data z_stream stream; // zLib stream structure for inflate uLong pos_in_zipfile; // position in byte on the zipfile, for fseek uLong stream_initialised; // flag set if stream structure is initialised uLong offset_local_extrafield;// offset of the local extra field uInt size_local_extrafield;// size of the local extra field uLong pos_local_extrafield; // position in the local extra field in read uLong crc32; // crc32 of all data uncompressed uLong crc32_wait; // crc32 we must obtain after decompress all uLong rest_read_compressed; // number of byte to be decompressed uLong rest_read_uncompressed;//number of byte to be obtained after decomp LUFILE* file; // io structore of the zipfile uLong compression_method; // compression method (0==store) uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) bool encrypted; // is it encrypted? unsigned long keys[3]; // decryption keys, initialized by unzOpenCurrentFile int encheadleft; // the first call(s) to unzReadCurrentFile will read this many encryption-header bytes first char crcenctest; // if encrypted, we'll check the encryption buffer against this } file_in_zip_read_info_s; // unz_s contain internal information about the zipfile typedef struct unz_ss { unz_ss(): file(0), byte_before_the_zipfile(0), num_file(0), pos_in_central_dir(0), current_file_ok(0), central_pos(0), size_central_dir(0), offset_central_dir(0), pfile_in_zip_read(0) { } LUFILE* file; // io structore of the zipfile unz_global_info gi; // public global information uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) uLong num_file; // number of the current file in the zipfile uLong pos_in_central_dir; // pos of the current file in the central dir uLong current_file_ok; // flag about the usability of the current file uLong central_pos; // position of the beginning of the central dir uLong size_central_dir; // size of the central directory uLong offset_central_dir; // offset of start of central directory with respect to the starting disk number unz_file_info cur_file_info; // public info about the current file in zip unz_file_info_internal cur_file_info_internal; // private info about it file_in_zip_read_info_s* pfile_in_zip_read; // structure about the current file if we are decompressing it } unz_s, *unzFile; int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity); // Compare two filename (fileName1,fileName2). z_off_t unztell (unzFile file); // Give the current position in uncompressed data int unzeof (unzFile file); // return 1 if the end of file was reached, 0 elsewhere int unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len); // Read extra field from the current file (opened by unzOpenCurrentFile) // This is the local-header version of the extra field (sometimes, there is // more info in the local-header version than in the central-header) // // if buf==NULL, it return the size of the local extra field // // if buf!=NULL, len is the size of the buffer, the extra header is copied in // buf. // the return value is the number of bytes copied in buf, or (if <0) // the error code // =========================================================================== // Read a byte from a gz_stream; update next_in and avail_in. Return EOF // for end of file. // IN assertion: the stream s has been successfully opened for reading. int unzlocal_getByte(LUFILE *fin,int *pi) { unsigned char c; int err = (int)lufread(&c, 1, 1, fin); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (luferror(fin)) return UNZ_ERRNO; else return UNZ_EOF; } } // =========================================================================== // Reads a long in LSB order from the given gz_stream. Sets int unzlocal_getShort (LUFILE *fin,uLong *pX) { uLong x ; int i; int err; err = unzlocal_getByte(fin,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } int unzlocal_getLong (LUFILE *fin,uLong *pX) { uLong x ; int i; int err; err = unzlocal_getByte(fin,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<16; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } // My own strcmpi / strcasecmp int strcmpcasenosensitive_internal (const char* fileName1,const char *fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= (char)0x20; if ((c2>='a') && (c2<='z')) c2 -= (char)0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } // // Compare two filename (fileName1,fileName2). // If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp) // If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi or strcasecmp) // int unzStringFileNameCompare (const char*fileName1,const char*fileName2,int iCaseSensitivity) { if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); else return strcmpcasenosensitive_internal(fileName1,fileName2); } #define BUFREADCOMMENT (0x400) // Locate the Central directory of a zipfile (at the end, just before // the global comment). Lu bugfix 2005.07.26 - returns 0xFFFFFFFF if not found, // rather than 0, since 0 is a valid central-dir-location for an empty zipfile. uLong unzlocal_SearchCentralDir(LUFILE *fin) { if (lufseek(fin,0,SEEK_END) != 0) return 0xFFFFFFFF; uLong uSizeFile = luftell(fin); uLong uMaxBack=0xffff; // maximum size of global comment if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; unsigned char *buf = (unsigned char*)zmalloc(BUFREADCOMMENT+4); if (buf==NULL) return 0xFFFFFFFF; uLong uPosFound=0xFFFFFFFF; uLong uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (lufseek(fin,uReadPos,SEEK_SET)!=0) break; if (lufread(buf,(uInt)uReadSize,1,fin)!=1) break; for (i=(int)uReadSize-3; (i--)>=0;) { if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } } if (uPosFound!=0) break; } if (buf) zfree(buf); return uPosFound; } int unzGoToFirstFile (unzFile file); int unzCloseCurrentFile (unzFile file); // Open a Zip file. // If the zipfile cannot be opened (file don't exist or in not valid), return NULL. // Otherwise, the return value is a unzFile Handle, usable with other unzip functions unzFile unzOpenInternal(LUFILE *fin) { if (fin==NULL) return NULL; if (unz_copyright[0]!=' ') {lufclose(fin); return NULL;} int err=UNZ_OK; unz_s us; uLong central_pos=0,uL=0; central_pos = unzlocal_SearchCentralDir(fin); if (central_pos==0xFFFFFFFF) err=UNZ_ERRNO; if (err==UNZ_OK && lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO; // the signature, already checked if (err==UNZ_OK && unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; // number of this disk uLong number_disk=0; // number of the current dist, used for spanning ZIP, unsupported, always 0 if (err==UNZ_OK && unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; // number of the disk with the start of the central directory uLong number_disk_with_CD=0; // number the disk with central dir, used for spaning ZIP, unsupported, always 0 if (err==UNZ_OK && unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; // total number of entries in the central dir on this disk if (err==UNZ_OK && unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; // total number of entries in the central dir uLong number_entry_CD=0; // total number of entries in the central dir (same than number_entry on nospan) if (err==UNZ_OK && unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if (err==UNZ_OK && ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))) err=UNZ_BADZIPFILE; // size of the central directory if (err==UNZ_OK && unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; // offset of start of central directory with respect to the starting disk number if (err==UNZ_OK && unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; // zipfile comment length if (err==UNZ_OK && unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; if (err==UNZ_OK && ((central_pos+fin->initial_offsetinitial_offset - (us.offset_central_dir+us.size_central_dir); us.central_pos = central_pos; us.pfile_in_zip_read = NULL; fin->initial_offset = 0; // since the zipfile itself is expected to handle this unz_s *s = (unz_s*)zmalloc(sizeof(unz_s)); *s=us; unzGoToFirstFile((unzFile)s); return (unzFile)s; } // Close a ZipFile opened with unzipOpen. // If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), // these files MUST be closed with unzipCloseCurrentFile before call unzipClose. // return UNZ_OK if there is no problem. int unzClose (unzFile file) { if (file==NULL) return UNZ_PARAMERROR; unz_s* s=(unz_s*)file; if (s->pfile_in_zip_read!=NULL) unzCloseCurrentFile(file); lufclose(s->file); zfree(s); return UNZ_OK; } // Write info about the ZipFile in the *pglobal_info structure. // No preparation of the structure is needed // return UNZ_OK if there is no problem. int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; *pglobal_info=s->gi; return UNZ_OK; } // Translate date/time from Dos format to tm_unz (readable more easilty) void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) { uLong uDate; uDate = (uLong)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } // Get Info about the current file in the zipfile, with internal only info int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize); int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz_s* s; unz_file_info file_info; unz_file_info_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) err=UNZ_ERRNO; // we check the magic if (err==UNZ_OK) { if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (lufread(szFileName,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; lSeek -= uSizeRead; } if ((err==UNZ_OK) && (extraField!=NULL)) { uLong uSizeRead ; if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) { if (lufread(extraField,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; } lSeek += file_info.size_file_extra - uSizeRead; } else lSeek+=file_info.size_file_extra; if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) {} // unused lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (lufread(szComment,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; //unused lSeek+=file_info.size_file_comment - uSizeRead; } else {} //unused lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } // Write info about the ZipFile in the *pglobal_info structure. // No preparation of the structure is needed // return UNZ_OK if there is no problem. int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } // Set the current file of the zipfile to the first file. // return UNZ_OK if there is no problem int unzGoToFirstFile (unzFile file) { int err; unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } // Set the current file of the zipfile to the next file. // return UNZ_OK if there is no problem // return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. int unzGoToNextFile (unzFile file) { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } // Try locate the file szFileName in the zipfile. // For the iCaseSensitivity signification, see unzStringFileNameCompare // return value : // UNZ_OK if the file is found. It becomes the current file. // UNZ_END_OF_LIST_OF_FILE if the file is not found int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) { unz_s* s; int err; uLong num_fileSaved; uLong pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; unzGetCurrentFileInfo(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (unzStringFileNameCompare(szCurrentFileName,szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; return err; } // Read the local header of the current zipfile // Check the coherency of the local header and info in the end of central // directory about this file // store in *piSizeVar the size of extra info in local header // (filename and size of extra field data) int unzlocal_CheckCurrentFileCoherencyHeader (unz_s *s,uInt *piSizeVar, uLong *poffset_local_extrafield, uInt *psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; // else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) // err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size compr err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } // Open for reading data the current file in the zipfile. // If there is no error and the file is opened, the return value is UNZ_OK. int unzOpenCurrentFile (unzFile file, const char *password) { int err; int Store; uInt iSizeVar; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uLong offset_local_extrafield; // offset of the local extra field uInt size_local_extrafield; // size of the local extra field if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip_read_info_s*)zmalloc(sizeof(file_in_zip_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)zmalloc(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; if (pfile_in_zip_read_info->read_buffer==NULL) { if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); //unused pfile_in_zip_read_info=0; return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) { // unused err=UNZ_BADZIPFILE; } Store = s->cur_file_info.compression_method==0; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->file=s->file; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if (!Store) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; err=inflateInit2(&pfile_in_zip_read_info->stream); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=1; // windowBits is passed < 0 to tell that there is no zlib header. // Note that in this case inflate *requires* an extra "dummy" byte // after the compressed stream in order to complete decompression and // return Z_STREAM_END. // In unzip, i don't wait absolutely Z_STREAM_END because I known the // size of both compressed and uncompressed data } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->encrypted = (s->cur_file_info.flag&1)!=0; bool extlochead = (s->cur_file_info.flag&8)!=0; if (extlochead) pfile_in_zip_read_info->crcenctest = (char)((s->cur_file_info.dosDate>>8)&0xff); else pfile_in_zip_read_info->crcenctest = (char)(s->cur_file_info.crc >> 24); pfile_in_zip_read_info->encheadleft = (pfile_in_zip_read_info->encrypted?12:0); pfile_in_zip_read_info->keys[0] = 305419896L; pfile_in_zip_read_info->keys[1] = 591751049L; pfile_in_zip_read_info->keys[2] = 878082192L; for (const char *cp=password; cp!=0 && *cp!=0; cp++) Uupdate_keys(pfile_in_zip_read_info->keys,*cp); pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; return UNZ_OK; } // Read bytes from the current file. // buf contain buffer where data must be copied // len the size of buf. // return the number of byte copied if somes bytes are copied (and also sets *reached_eof) // return 0 if the end of file was reached. (and also sets *reached_eof). // return <0 with error code if there is an error. (in which case *reached_eof is meaningless) // (UNZ_ERRNO for IO error, or zLib error for uncompress error) int unzReadCurrentFile (unzFile file, voidp buf, unsigned len, bool *reached_eof) { int err=UNZ_OK; uInt iRead = 0; if (reached_eof!=0) *reached_eof=false; unz_s *s = (unz_s*)file; if (s==NULL) return UNZ_PARAMERROR; file_in_zip_read_info_s* pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Byte*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if (len>pfile_in_zip_read_info->rest_read_uncompressed) { pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; } while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) {if (reached_eof!=0) *reached_eof=true; return UNZ_EOF;} if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; if (lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Byte*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; // if (pfile_in_zip_read_info->encrypted) { char *buf = (char*)pfile_in_zip_read_info->stream.next_in; for (unsigned int i=0; ikeys,buf[i]); } } unsigned int uDoEncHead = pfile_in_zip_read_info->encheadleft; if (uDoEncHead>pfile_in_zip_read_info->stream.avail_in) uDoEncHead=pfile_in_zip_read_info->stream.avail_in; if (uDoEncHead>0) { char bufcrc=pfile_in_zip_read_info->stream.next_in[uDoEncHead-1]; pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead; pfile_in_zip_read_info->stream.avail_in -= uDoEncHead; pfile_in_zip_read_info->stream.next_in += uDoEncHead; pfile_in_zip_read_info->encheadleft -= uDoEncHead; if (pfile_in_zip_read_info->encheadleft==0) { if (bufcrc!=pfile_in_zip_read_info->crcenctest) return UNZ_PASSWORD; } } if (pfile_in_zip_read_info->compression_method==0) { uInt uDoCopy,i ; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) { uDoCopy = pfile_in_zip_read_info->stream.avail_out ; } else { uDoCopy = pfile_in_zip_read_info->stream.avail_in ; } for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,pfile_in_zip_read_info->stream.next_out,uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; if (pfile_in_zip_read_info->rest_read_uncompressed==0) {if (reached_eof!=0) *reached_eof=true;} } else { uLong uTotalOutBefore,uTotalOutAfter; const Byte *bufBefore; uLong uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; // err=inflate(&pfile_in_zip_read_info->stream,flush); // uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,bufBefore,(uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END || pfile_in_zip_read_info->rest_read_uncompressed==0) { if (reached_eof!=0) *reached_eof=true; return iRead; } if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } // Give the current position in uncompressed data z_off_t unztell (unzFile file) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } // return 1 if the end of file was reached, 0 elsewhere int unzeof (unzFile file) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } // Read extra field from the current file (opened by unzOpenCurrentFile) // This is the local-header version of the extra field (sometimes, there is // more info in the local-header version than in the central-header) // if buf==NULL, it return the size of the local extra field that can be read // if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. // the return value is the number of bytes copied in buf, or (if <0) the error code int unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uInt read_now; uLong size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) return UNZ_ERRNO; if (lufread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; return (int)read_now; } // Close the file in zip opened with unzipOpenCurrentFile // Return UNZ_CRCERROR if all the file was read but the CRC is not good int unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } if (pfile_in_zip_read_info->read_buffer!=0) { void *buf = pfile_in_zip_read_info->read_buffer; zfree(buf); pfile_in_zip_read_info->read_buffer=0; } pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); pfile_in_zip_read_info->stream_initialised = 0; if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; s->pfile_in_zip_read=NULL; return err; } // Get the global comment string of the ZipFile, in the szComment buffer. // uSizeBuf is the size of the szComment buffer. // return the number of byte copied or an error code <0 int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) { //int err=UNZ_OK; unz_s* s; uLong uReadThis ; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (lufseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (lufread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } int unzOpenCurrentFile (unzFile file, const char *password); int unzReadCurrentFile (unzFile file, void *buf, unsigned len); int unzCloseCurrentFile (unzFile file); class TUnzip { public: TUnzip(const char *pwd) : uf(0), currentfile(-1), czei(-1), password(0), unzbuf(0) { if (pwd!=0) { password=new char[strlen(pwd)+1]; strncpy(password,pwd,strlen(pwd)+1); } } ~TUnzip() {if (password!=0) delete[] password; password=0; if (unzbuf!=0) delete[] unzbuf; unzbuf=0;} unzFile uf; int currentfile; ZIPENTRY cze; int czei; char *password; char *unzbuf; // lazily created and destroyed, used by Unzip TCHAR rootdir[MAX_PATH]; // includes a trailing slash ZRESULT Open(void *z,unsigned int len,DWORD flags); ZRESULT Get(int index,ZIPENTRY *ze); ZRESULT Find(const TCHAR *name,bool ic,int *index,ZIPENTRY *ze); ZRESULT Unzip(int index,void *dst,unsigned int len,DWORD flags); ZRESULT SetUnzipBaseDir(const TCHAR *dir); ZRESULT Close(); }; ZRESULT TUnzip::Open(void *z,unsigned int len,DWORD flags) { if (uf!=0 || currentfile!=-1) return ZR_NOTINITED; // #ifdef ZIP_STD char* buf = GETCWD(rootdir,MAX_PATH-1); if (buf==0) return ZR_NOFILE; #else #ifdef GetCurrentDirectory GetCurrentDirectory(MAX_PATH-1,rootdir); #else rootdir[0]='/'; rootdir[1]=0; #endif #endif TCHAR *lastchar = &rootdir[_tcslen(rootdir)-1]; if (*lastchar!='\\' && *lastchar!='/') {lastchar[1]='/'; lastchar[2]=0;} // if (flags==ZIP_HANDLE) { // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. DWORD res = GetFilePosU((HANDLE)z); bool canseek = (res!=0xFFFFFFFF); if (!canseek) return ZR_SEEK; } ZRESULT e; LUFILE *f = lufopen(z,len,flags,&e); if (f==NULL) return e; uf = unzOpenInternal(f); if (uf==0) return ZR_NOFILE; return ZR_OK; } ZRESULT TUnzip::SetUnzipBaseDir(const TCHAR *dir) { #ifdef ZIP_STD strncpy(rootdir,dir,MAX_PATH-1); #else _tcsncpy_s(rootdir,MAX_PATH,dir,MAX_PATH-1); #endif TCHAR *lastchar = &rootdir[_tcslen(rootdir)-1]; if (*lastchar!='\\' && *lastchar!='/') {lastchar[1]='/'; lastchar[2]=0;} return ZR_OK; } ZRESULT TUnzip::Get(int index,ZIPENTRY *ze) { if (index<-1 || index>=(int)uf->gi.number_entry) return ZR_ARGS; if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (index==czei && index!=-1) {memcpy(ze,&cze,sizeof(ZIPENTRY)); return ZR_OK;} if (index==-1) { ze->index = uf->gi.number_entry; ze->name[0]=0; ze->attr=0; #ifdef ZIP_STD ze->atime=0; ze->ctime=0; ze->mtime=0; #else ze->atime.dwLowDateTime=0; ze->atime.dwHighDateTime=0; ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0; ze->mtime.dwLowDateTime=0; ze->mtime.dwHighDateTime=0; #endif ze->comp_size=0; ze->unc_size=0; return ZR_OK; } if (index<(int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_filefile,offset,SEEK_SET)!=0) return ZR_READ; unsigned char *extra = new unsigned char[extralen]; if (lufread(extra,1,(uInt)extralen,uf->file)!=extralen) {delete[] extra; return ZR_READ;} // ze->index=uf->num_file; TCHAR tfn[MAX_PATH]; #ifdef UNICODE MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH); #else // strcpy_s(tfn,MAX_PATH,fn); strncpy(tfn,fn,MAX_PATH); #endif // As a safety feature: if the zip filename had sneaky stuff // like "c:\windows\file.txt" or "\windows\file.txt" or "fred\..\..\..\windows\file.txt" // then we get rid of them all. That way, when the programmer does UnzipItem(hz,i,ze.name), // it won't be a problem. (If the programmer really did want to get the full evil information, // then they can edit out this security feature from here). // In particular, we chop off any prefixes that are "c:\" or "\" or "/" or "[stuff]\.." or "[stuff]/.." const TCHAR *sfn=tfn; for (;;) { if (sfn[0]!=0 && sfn[1]==':') {sfn+=2; continue;} if (sfn[0]=='\\') {sfn++; continue;} if (sfn[0]=='/') {sfn++; continue;} const TCHAR *c; c=_tcsstr(sfn,_T("\\..\\")); if (c!=0) {sfn=c+4; continue;} c=_tcsstr(sfn,_T("\\../")); if (c!=0) {sfn=c+4; continue;} c=_tcsstr(sfn,_T("/../")); if (c!=0) {sfn=c+4; continue;} c=_tcsstr(sfn,_T("/..\\")); if (c!=0) {sfn=c+4; continue;} break; } #ifdef ZIP_STD strncpy(ze->name,sfn,MAX_PATH); #else _tcsncpy_s(ze->name,MAX_PATH, sfn,MAX_PATH); #endif unsigned long a = ufi.external_fa; // zip has an 'attribute' 32bit value. Its lower half is windows stuff // its upper half is standard unix stat.st_mode. We'll start trying // to read it in unix mode bool isdir = (a&0x40000000)!=0; bool readonly= (a&0x00800000)==0; //bool readable= (a&0x01000000)!=0; // unused //bool executable=(a&0x00400000)!=0; // unused // but in normal hostmodes these are overridden by the lower half... int host = ufi.version>>8; if (host==0 || host==7 || host==11 || host==14) { readonly= (a&0x00000001)!=0; isdir= (a&0x00000010)!=0; } // readonly; hidden; system; isdir; archive; ze->attr=0; #ifdef ZIP_STD ze->attr = (a&0xFFFF0000)>>16; if (isdir) ze->attr |= S_IFDIR; if (readonly) ze->attr &= ~S_IWUSR; #else bool hidden=false, system=false, archive=true; if (host==0 || host==7 || host==11 || host==14) { hidden= (a&0x00000002)!=0; system= (a&0x00000004)!=0; archive= (a&0x00000020)!=0; } if (isdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY; if (readonly) ze->attr|=FILE_ATTRIBUTE_READONLY; if (archive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE; if (hidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN; if (system) ze->attr|=FILE_ATTRIBUTE_SYSTEM; #endif ze->comp_size = ufi.compressed_size; ze->unc_size = ufi.uncompressed_size; // WORD dostime = (WORD)(ufi.dosDate&0xFFFF); WORD dosdate = (WORD)((ufi.dosDate>>16)&0xFFFF); FILETIME ftd = dosdatetime2filetime(dosdate,dostime); FILETIME ft; LocalFileTimeToFileTime(&ftd,&ft); ze->atime=ft; ze->ctime=ft; ze->mtime=ft; // the zip will always have at least that dostime. But if it also has // an extra header, then we'll instead get the info from that. unsigned int epos=0; while (epos+4mtime = timet2filetime(mtime); } if (hasatime) { lutime_t atime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); epos+=4; ze->atime = timet2filetime(atime); } if (hasctime) { lutime_t ctime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); epos+=4; ze->ctime = timet2filetime(ctime); } break; } // if (extra!=0) delete[] extra; memcpy(&cze,ze,sizeof(ZIPENTRY)); czei=index; return ZR_OK; } ZRESULT TUnzip::Find(const TCHAR *tname,bool ic,int *index,ZIPENTRY *ze) { char name[MAX_PATH]; #ifdef UNICODE WideCharToMultiByte(CP_UTF8,0,tname,-1,name,MAX_PATH,0,0); #else // strcpy_s(name,MAX_PATH,tname); strncpy(name,tname, MAX_PATH); #endif int res = unzLocateFile(uf,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE); if (res!=UNZ_OK) { if (index!=0) *index=-1; if (ze!=NULL) {memset(ze,0,sizeof(ZIPENTRY)); ze->index=-1;} return ZR_NOTFOUND; } if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; int i = (int)uf->num_file; if (index!=NULL) *index=i; if (ze!=NULL) { ZRESULT zres = Get(i,ze); if (zres!=ZR_OK) return zres; } return ZR_OK; } void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) { // first check that rootdir exists. nb. rootdir has a trailing slash if (rootdir!=0) { TCHAR rd[MAX_PATH+1]; #ifdef ZIP_STD strncpy(rd,rootdir,MAX_PATH); #else _tcsncpy_s(rd,MAX_PATH,rootdir,MAX_PATH); #endif // make sure there rd is always null terminated rd[MAX_PATH] = 0; size_t len=_tcslen(rd); if (len>0 && (rd[len-1]=='/' || rd[len-1]=='\\')) rd[len-1]=0; #ifdef ZIP_STD if (!FileExists(rd)) lumkdir(rd); #else if (!FileExists(rd)) CreateDirectory(rd,0); #endif } if (*dir==0) return; const TCHAR *lastslash=dir, *c=lastslash; while (*c!=0) {if (*c=='/' || *c=='\\') lastslash=c; c++;} const TCHAR *name=lastslash; if (lastslash!=dir) { TCHAR tmp[MAX_PATH]; memcpy(tmp,dir,sizeof(TCHAR)*(lastslash-dir)); tmp[lastslash-dir]=0; EnsureDirectory(rootdir,tmp); name++; } TCHAR cd[MAX_PATH]; *cd=0; if (rootdir!=0) #ifdef ZIP_STD strncpy(cd,rootdir,MAX_PATH); #else _tcsncpy_s(cd,MAX_PATH,rootdir,MAX_PATH); #endif cd[MAX_PATH-1]=0; size_t len=_tcslen(cd); #ifdef ZIP_STD strncpy(cd+len,dir,MAX_PATH-len); #else _tcsncpy_s(cd+len,MAX_PATH-len,dir,MAX_PATH-len); #endif cd[MAX_PATH-1]=0; #ifdef ZIP_STD if (!FileExists(cd)) lumkdir(cd); #else if (!FileExists(cd)) { CreateDirectory(cd,0); } #endif } ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) { if (flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE) return ZR_ARGS; if (flags==ZIP_MEMORY) { if (index!=currentfile) { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (index>=(int)uf->gi.number_entry) return ZR_ARGS; if (index<(int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file0) { return ZR_MORE; } if (res==UNZ_PASSWORD) { return ZR_PASSWORD; } return ZR_FLATE; } // otherwise we're writing to a handle or a file if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (index>=(int)uf->gi.number_entry) return ZR_ARGS; if (index<(int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file0) {size_t writ=fwrite(unzbuf,1,res,h); if (writ<(size_t)res) {haderr=ZR_WRITE; break;}} #else if (res>0) {DWORD writ; BOOL bres=WriteFile(h,unzbuf,res,&writ,NULL); if (!bres) {haderr=ZR_WRITE; break;}} #endif if (reached_eof) break; if (res==0) {haderr=ZR_FLATE; break;} } unzCloseCurrentFile(uf); #ifdef ZIP_STD if (flags!=ZIP_HANDLE) fclose(h); if (*fn!=0) {struct utimbuf ubuf; ubuf.actime=ze.atime; ubuf.modtime=ze.mtime; utime(fn,&ubuf);} #else if (!haderr) SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); // may fail if it was a pipe if (flags!=ZIP_HANDLE) CloseHandle(h); #endif if (haderr!=0) return haderr; return ZR_OK; } ZRESULT TUnzip::Close() { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (uf!=0) unzClose(uf); uf=0; return ZR_OK; } ZRESULT lasterrorU=ZR_OK; unsigned int FormatZipMessageU(ZRESULT code, TCHAR *buf,unsigned int len) { if (code==ZR_RECENT) code=lasterrorU; const TCHAR *msg=_T("unknown zip result code"); switch (code) { case ZR_OK: msg=_T("Success"); break; case ZR_NODUPH: msg=_T("Culdn't duplicate handle"); break; case ZR_NOFILE: msg=_T("Couldn't create/open file"); break; case ZR_NOALLOC: msg=_T("Failed to allocate memory"); break; case ZR_WRITE: msg=_T("Error writing to file"); break; case ZR_NOTFOUND: msg=_T("File not found in the zipfile"); break; case ZR_MORE: msg=_T("Still more data to unzip"); break; case ZR_CORRUPT: msg=_T("Zipfile is corrupt or not a zipfile"); break; case ZR_READ: msg=_T("Error reading file"); break; case ZR_PASSWORD: msg=_T("Correct password required"); break; case ZR_ARGS: msg=_T("Caller: faulty arguments"); break; case ZR_PARTIALUNZ: msg=_T("Caller: the file had already been partially unzipped"); break; case ZR_NOTMMAP: msg=_T("Caller: can only get memory of a memory zipfile"); break; case ZR_MEMSIZE: msg=_T("Caller: not enough space allocated for memory zipfile"); break; case ZR_FAILED: msg=_T("Caller: there was a previous error"); break; case ZR_ENDED: msg=_T("Caller: additions to the zip have already been ended"); break; case ZR_ZMODE: msg=_T("Caller: mixing creation and opening of zip"); break; case ZR_NOTINITED: msg=_T("Zip-bug: internal initialisation not completed"); break; case ZR_SEEK: msg=_T("Zip-bug: trying to seek the unseekable"); break; case ZR_MISSIZE: msg=_T("Zip-bug: the anticipated size turned out wrong"); break; case ZR_NOCHANGE: msg=_T("Zip-bug: tried to change mind, but not allowed"); break; case ZR_FLATE: msg=_T("Zip-bug: an internal error during flation"); break; } unsigned int mlen=(unsigned int)_tcslen(msg); if (buf==0 || len==0) return mlen; unsigned int n=mlen; if (n+1>len) n=len-1; #ifdef ZIP_STD strncpy(buf,msg,n); #else _tcsncpy_s(buf,_tcslen(buf),msg,n); #endif buf[n]=0; return mlen; } typedef struct { DWORD flag; TUnzip *unz; } TUnzipHandleData; HZIP OpenZipInternal(void *z,unsigned int len,DWORD flags, const char *password) { TUnzip *unz = new TUnzip(password); lasterrorU = unz->Open(z,len,flags); if (lasterrorU!=ZR_OK) {delete unz; return 0;} TUnzipHandleData *han = new TUnzipHandleData; han->flag=1; han->unz=unz; return (HZIP)han; } HZIP OpenZipHandle(HANDLE h, const char *password) {return OpenZipInternal((void*)h,0,ZIP_HANDLE,password);} HZIP OpenZip(const TCHAR *fn, const char *password) {return OpenZipInternal((void*)fn,0,ZIP_FILENAME,password);} HZIP OpenZip(void *z,unsigned int len, const char *password) {return OpenZipInternal(z,len,ZIP_MEMORY,password);} ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze) { ze->index=0; *ze->name=0; ze->unc_size=0; if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Get(index,ze); return lasterrorU; } ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Find(name,ic,index,ze); return lasterrorU; } ZRESULT UnzipItemInternal(HZIP hz, int index, void *dst, unsigned int len, DWORD flags) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Unzip(index,dst,len,flags); return lasterrorU; } ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h) {return UnzipItemInternal(hz,index,(void*)h,0,ZIP_HANDLE);} ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn) {return UnzipItemInternal(hz,index,(void*)fn,0,ZIP_FILENAME);} ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len) {return UnzipItemInternal(hz,index,z,len,ZIP_MEMORY);} ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->SetUnzipBaseDir(dir); return lasterrorU; } ZRESULT CloseZipU(HZIP hz) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Close(); delete unz; delete han; return lasterrorU; } bool IsZipHandleU(HZIP hz) { if (hz==0) return false; TUnzipHandleData *han = (TUnzipHandleData*)hz; return (han->flag==1); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/0000755000175000017500000000000013151044751022735 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/OpenGLESGeometryOptimizer0000644000175000017500000001012013151044751027645 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef OPENGLES_GEOMETRY_OPTIMIZER #define OPENGLES_GEOMETRY_OPTIMIZER #include #include //std::max #include "AnimationVisitor" #include "BindPerVertexVisitor" #include "DetachPrimitiveVisitor" #include "DrawArrayVisitor" #include "GeometrySplitterVisitor" #include "IndexMeshVisitor" #include "PreTransformVisitor" #include "TangentSpaceVisitor" #include "TriangleStripVisitor" #include "UnIndexMeshVisitor" #include "WireframeVisitor" class OpenGLESGeometryOptimizer { public: OpenGLESGeometryOptimizer() : _useDrawArray(false), _disableTriStrip(false), _disableMergeTriStrip(false), _disablePreTransform(false), _disablePostTransform(false), _triStripCacheSize(16), _triStripMinSize(2), _generateTangentSpace(false), _tangentUnit(0), _maxIndexValue(65535), _wireframe("") {} // run the optimizer osg::Node* optimize(osg::Node& node); // handle options void setUseDrawArray(bool s) { _useDrawArray = s; } void setDisableTriStrip(bool s) { _disableTriStrip = s; } void setDisableMergeTriStrip(bool s) { _disableMergeTriStrip = s; } void setDisablePreTransform(bool s) { _disablePreTransform = s; } void setDisablePostTransform(bool s) { _disablePostTransform = s; } void setTripStripCacheSize(unsigned int size) { _triStripCacheSize = size; } void setTripStripMinSize(unsigned int size) { _triStripMinSize = std::max(size, 2); } void setTexCoordChannelForTangentSpace(int uv) { _tangentUnit = uv; _generateTangentSpace = true; } void setMaxIndexValue(unsigned int s) { _maxIndexValue = s; } void setWireframe(const std::string& s) { _wireframe = s; if(_wireframe == std::string("outline")) { // no use to build strip if we only want wireframe setDisableTriStrip(true); } } protected: void makeAnimation(osg::Node* node) { AnimationVisitor anim; node->accept(anim); } void makeWireframe(osg::Node* node) { WireframeVisitor wireframe(_wireframe == std::string("inline")); node->accept(wireframe); } void makeBindPerVertex(osg::Node* node) { BindPerVertexVisitor bindpervertex; node->accept(bindpervertex); } void makeIndexMesh(osg::Node* node) { IndexMeshVisitor indexer; node->accept(indexer); } void makeTangentSpace(osg::Node* node) { TangentSpaceVisitor tangent(_tangentUnit); node->accept(tangent); } void makeSplit(osg::Node* node) { GeometrySplitterVisitor splitter(_maxIndexValue, _disablePostTransform); node->accept(splitter); } void makeTriStrip(osg::Node* node) { TriangleStripVisitor strip(_triStripCacheSize, _triStripMinSize, !_disableMergeTriStrip); node->accept(strip); } void makeDrawArray(osg::Node* node) { DrawArrayVisitor drawarray; node->accept(drawarray); } void makePreTransform(osg::Node* node) { PreTransformVisitor preTransform; node->accept(preTransform); } void makeDetach(osg::Node* node) { DetachPrimitiveVisitor detacher("wireframe", false, _wireframe == std::string("inline")); node->accept(detacher); } bool _useDrawArray; bool _disableTriStrip; bool _disableMergeTriStrip; bool _disablePreTransform; bool _disablePostTransform; unsigned int _triStripCacheSize; unsigned int _triStripMinSize; bool _generateTangentSpace; int _tangentUnit; unsigned int _maxIndexValue; std::string _wireframe; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/GeometryUniqueVisitor0000644000175000017500000000343013151044751027222 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef GEOMETRY_UNIQUE_VISITOR_H #define GEOMETRY_UNIQUE_VISITOR_H #include #include #include #include #include #include "StatLogger" class GeometryUniqueVisitor : public osg::NodeVisitor { public: GeometryUniqueVisitor(const std::string label=std::string("GeometryUniqueVisitor")): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _logger(formatStatLabel(label)) {} virtual void apply(osg::Geode& geode){ for (unsigned int i = 0; i < geode.getNumDrawables(); i++) { apply(*geode.getDrawable(i)); } } virtual void apply(osg::Drawable& drawable){ osg::Geometry* geometry = drawable.asGeometry(); if (!geometry || isProcessed(geometry)) { return; } apply(*geometry); } virtual void apply(osg::Geometry& geometry) {} // to be implemented by actual visitors protected: bool isProcessed(osg::Geometry* node) { return _processed.find(node) != _processed.end(); } void setProcessed(osg::Geometry* node) { _processed.insert(node); } std::string formatStatLabel(const std::string& label) const { return label + "::apply(..)"; } std::set _processed; StatLogger _logger; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/EdgeIndexFunctor0000644000175000017500000002026413151044751026061 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef EDGE_INDEX_FUNCTOR_H #define EDGE_INDEX_FUNCTOR_H #include #include template class EdgeIndexFunctor : public osg::PrimitiveIndexFunctor, public T { public: virtual void setVertexArray(unsigned int,const osg::Vec2*) {} virtual void setVertexArray(unsigned int ,const osg::Vec3* ) {} virtual void setVertexArray(unsigned int,const osg::Vec4* ) {} virtual void setVertexArray(unsigned int,const osg::Vec2d*) {} virtual void setVertexArray(unsigned int ,const osg::Vec3d* ) {} virtual void setVertexArray(unsigned int,const osg::Vec4d* ) {} virtual void begin(GLenum mode) { _modeCache = mode; _indexCache.clear(); } virtual void vertex(unsigned int vert) { _indexCache.push_back(vert); } virtual void end() { if (!_indexCache.empty()) { drawElements(_modeCache, _indexCache.size(), &_indexCache.front()); } } virtual void drawArrays(GLenum mode, GLint first, GLsizei count) { switch(mode) { case(GL_TRIANGLES): { unsigned int pos=first; for(GLsizei i = 2 ; i < count ; i += 3, pos += 3) { this->operator()(pos, pos+1); this->operator()(pos+1, pos+2); this->operator()(pos+2, pos); } break; } case(GL_TRIANGLE_STRIP): { unsigned int pos=first; for(GLsizei i = 2 ; i < count ; ++ i, ++ pos) { if ((i % 2)) { this->operator()(pos, pos+2); this->operator()(pos+2, pos+1); this->operator()(pos+1, pos); } else { this->operator()(pos, pos+1); this->operator()(pos+1, pos+2); this->operator()(pos, pos+2); } } break; } case(GL_QUADS): { unsigned int pos=first; for(GLsizei i = 3 ; i < count ; i += 4, pos += 4) { this->operator()(pos, pos+1); this->operator()(pos+1, pos+2); this->operator()(pos+2, pos+3); this->operator()(pos+3, pos); } break; } case(GL_QUAD_STRIP): { unsigned int pos=first; for(GLsizei i = 3 ; i < count ; i += 2, pos += 2) { this->operator()(pos, pos+1); this->operator()(pos+1, pos+3); this->operator()(pos+2, pos+3); this->operator()(pos+2, pos); } break; } case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN case(GL_TRIANGLE_FAN): { unsigned int pos=first+1; for(GLsizei i = 2 ; i < count ; ++ i, ++ pos) { this->operator()(pos, pos+1); } break; } case(GL_LINES): { unsigned int pos=first; for(GLsizei i = 0 ; i < count ; i += 2, pos += 2) { this->operator()(pos, pos+1); } } break; case(GL_LINE_STRIP): { unsigned int pos=first; for(GLsizei i = 0 ; i < count - 1 ; i += 1, pos += 1) { this->operator()(pos, pos+1); } } break; case(GL_LINE_LOOP): { unsigned int pos=first; for(GLsizei i = 0 ; i < count - 1; i += 1, pos += 1) { this->operator()(pos, pos+1); } this->operator()(pos, first); } break; case(GL_POINTS): break; default: // can't be converted into to edges. break; } } template void drawElements(GLenum mode, GLsizei count, const I* indices) { if (indices == 0 || count == 0) return; switch(mode) { case(GL_TRIANGLES): { const I* ilast = &indices[count]; for(const I* iptr = indices ; iptr < ilast ; iptr += 3) { this->operator()(*iptr, *(iptr+1)); this->operator()(*(iptr+1), *(iptr+2)); this->operator()(*iptr, *(iptr+2)); } break; } case(GL_TRIANGLE_STRIP): { const I* iptr = indices; for(GLsizei i = 2 ; i < count ; ++ i, ++ iptr) { I v0 = *(iptr), v1 = *(iptr + 1), v2 = *(iptr + 2); // when merging strips we create degenerate triangles and add // non existing edges that should be filtered if(v0 == v1 || v0 == v2 || v1 == v2) continue; if ((i % 2)) { this->operator()(v0, v2); this->operator()(v2, v1); this->operator()(v0, v1); } else { this->operator()(v0, v1); this->operator()(v1, v2); this->operator()(v0, v2); } } break; } case(GL_QUADS): { const I* iptr = indices; for(GLsizei i = 3 ; i < count ; i += 4, iptr += 4) { this->operator()(*(iptr), *(iptr+1)); this->operator()(*(iptr+1), *(iptr+2)); this->operator()(*(iptr+2), *(iptr+3) ); this->operator()(*(iptr), *(iptr+3) ); } break; } case(GL_QUAD_STRIP): { const I* iptr = indices; for(GLsizei i = 3 ; i < count ; i += 2, iptr += 2) { this->operator()(*(iptr), *(iptr+1)); this->operator()(*(iptr+3), *(iptr+1)); this->operator()(*(iptr+2), *(iptr+3)); this->operator()(*(iptr), *(iptr+2)); } break; } case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN case(GL_TRIANGLE_FAN): { const I* iptr = indices; ++iptr; for(GLsizei i = 2 ; i < count ; ++ i, ++ iptr) { this->operator()(*(iptr), *(iptr+1)); } break; } case(GL_LINES): { const I* iptr = indices; for(GLsizei i = 0 ; i < count - 1 ; i += 2, iptr += 2) { this->operator()(*iptr, *(iptr+1)); } } break; case(GL_LINE_STRIP): { const I* iptr = indices; for(GLsizei i = 0 ; i < count - 1 ; i += 1, iptr += 1) { this->operator()(*iptr, *(iptr+1)); } } break; case(GL_LINE_LOOP): { const I* iptr = indices; I first = *iptr; for(GLsizei i = 0 ; i < count - 1 ; i += 1, iptr += 1) { this->operator()(*iptr, *(iptr+1)); } this->operator()(*iptr, first); } break; case(GL_POINTS): break; default: // can't be converted into to edge lines break; } } virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices) { drawElements(mode, count, indices); } virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices) { drawElements(mode, count, indices); } virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices) { drawElements(mode, count, indices); } GLenum _modeCache; std::vector _indexCache; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/TangentSpaceVisitor0000644000175000017500000001002313151044751026610 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef TANGENT_SPACE_VISITOR #define TANGENT_SPACE_VISITOR #define TANGENT_ATTRIBUTE_INDEX 20 #include #include // {get,set}UserValue #include #include "GeometryUniqueVisitor" // we will store only tangent and rebuilt tangent2 in the vertex shader // http://www.terathon.com/code/tangent.html class TangentSpaceVisitor : public GeometryUniqueVisitor { public: TangentSpaceVisitor(int textureUnit = 0): GeometryUniqueVisitor("TangentSpaceVisitor"), _textureUnit(textureUnit) {} void apply(osg::Geometry& geom) { if (!geom.getTexCoordArray(_textureUnit)){ int texUnit = 0; bool found = false; while(texUnit < 32){ if (_textureUnit != texUnit && geom.getTexCoordArray(texUnit)){ _textureUnit = texUnit; found = true; break; } texUnit++; } if (!found) return; } osg::ref_ptr generator = new osgUtil::TangentSpaceGenerator; generator->generate(&geom, _textureUnit); // keep original normal array if (!geom.getNormalArray()) { if (generator->getNormalArray()) { osg::Vec3Array* vec3Normals = new osg::Vec3Array(); osg::Vec4Array* vec4Normals = generator->getNormalArray(); for (unsigned int i = 0; i < vec4Normals->size(); i++) { osg::Vec3 n = osg::Vec3((*vec4Normals)[i][0], (*vec4Normals)[i][1], (*vec4Normals)[i][2]); vec3Normals->push_back(n); } geom.setNormalArray(vec3Normals, osg::Array::BIND_PER_VERTEX); } } if (generator->getTangentArray()) { osg::Vec4Array* normal = generator->getNormalArray(); osg::Vec4Array* tangent = generator->getTangentArray(); osg::Vec4Array* tangent2 = generator->getBinormalArray(); osg::Vec4Array* finalTangent = dynamic_cast(generator->getTangentArray() ->clone(osg::CopyOp::DEEP_COPY_ALL)); for (unsigned int i = 0; i < tangent->size(); i++) { osg::Vec3 n = osg::Vec3((*normal)[i][0], (*normal)[i][1], (*normal)[i][2]); osg::Vec3 t = osg::Vec3((*tangent)[i][0], (*tangent)[i][1], (*tangent)[i][2]); osg::Vec3 t2 = osg::Vec3((*tangent2)[i][0], (*tangent2)[i][1], (*tangent2)[i][2]); // Gram-Schmidt orthogonalize osg::Vec3 t3 = (t - n * (n * t)); t3.normalize(); (*finalTangent)[i] = osg::Vec4(t3, 0.0); // Calculate handedness (*finalTangent)[i][3] = (((n ^ t) * t2) < 0.0) ? -1.0 : 1.0; // The bitangent vector B is then given by B = (N × T) · Tw } finalTangent->setUserValue("tangent", true); geom.setVertexAttribArray(geom.getNumVertexAttribArrays(), finalTangent, osg::Array::BIND_PER_VERTEX); } setProcessed(&geom); } protected: int _textureUnit; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/GeometryArray0000644000175000017500000003020013151044751025445 0ustar albertoalberto/* -*-c++-*- */ #ifndef GEOMETRY_ARRAY_UTILS_H #define GEOMETRY_ARRAY_UTILS_H #include #include #include #include typedef std::vector IndexList; struct GeometryArrayList { class ArrayIndexAppendVisitor : public osg::ArrayVisitor { public: ArrayIndexAppendVisitor(const IndexList& indexes, osg::Array* dst): _indexes(indexes), _dst(dst) { } const IndexList& _indexes; osg::Array* _dst; template inline void copy(T& array) { if (!_dst) { osg::notify(osg::WARN) << "Can't append to array null" << std::endl; return; } T* dstArray = dynamic_cast(_dst); for(IndexList::const_iterator it = _indexes.begin(); it != _indexes.end(); ++it) { unsigned int idx = *it; dstArray->push_back(array[idx]); } } virtual void apply(osg::Array&) {} virtual void apply(osg::ByteArray& array) { copy(array); } virtual void apply(osg::ShortArray& array) { copy(array); } virtual void apply(osg::IntArray& array) { copy(array); } virtual void apply(osg::UByteArray& array) { copy(array); } virtual void apply(osg::UShortArray& array) { copy(array); } virtual void apply(osg::UIntArray& array) { copy(array); } virtual void apply(osg::FloatArray& array) { copy(array); } virtual void apply(osg::DoubleArray& array) { copy(array); } virtual void apply(osg::Vec2Array& array) { copy(array); } virtual void apply(osg::Vec3Array& array) { copy(array); } virtual void apply(osg::Vec4Array& array) { copy(array); } virtual void apply(osg::Vec4ubArray& array) { copy(array); } virtual void apply(osg::Vec2bArray& array) { copy(array); } virtual void apply(osg::Vec3bArray& array) { copy(array); } virtual void apply(osg::Vec4bArray& array) { copy(array); } virtual void apply(osg::Vec2sArray& array) { copy(array); } virtual void apply(osg::Vec3sArray& array) { copy(array); } virtual void apply(osg::Vec4sArray& array) { copy(array); } virtual void apply(osg::Vec2dArray& array) { copy(array); } virtual void apply(osg::Vec3dArray& array) { copy(array); } virtual void apply(osg::Vec4dArray& array) { copy(array); } virtual void apply(osg::MatrixfArray& array) { copy(array); } protected: ArrayIndexAppendVisitor& operator = (const ArrayIndexAppendVisitor&) { return *this; } }; struct ArrayAppendElement { template bool arrayAppendElement(osg::Array* src, unsigned int index, osg::Array* dst) { T* array= dynamic_cast(src); if (array) { T* arrayDst = dynamic_cast(dst); arrayDst->push_back((*array)[index]); return true; } return false; } void operator()(osg::Array* src, unsigned int index, osg::Array* dst) { if (arrayAppendElement(src, index, dst)) return; if (arrayAppendElement(src, index, dst)) return; if (arrayAppendElement(src, index, dst)) return; if (arrayAppendElement(src, index, dst)) return; if (arrayAppendElement(src, index, dst)) return; } }; struct ArraySetNumElements { template bool arraySetNumElements(osg::Array* src, unsigned int numElements) { T* array= dynamic_cast(src); if (array) { array->resize(numElements); return true; } return false; } void operator()(osg::Array* array, unsigned int numElements) { if (arraySetNumElements(array, numElements)) return; if (arraySetNumElements(array, numElements)) return; if (arraySetNumElements(array, numElements)) return; if (arraySetNumElements(array, numElements)) return; if (arraySetNumElements(array, numElements)) return; } }; osg::ref_ptr _vertexes; osg::ref_ptr _normals; osg::ref_ptr _colors; osg::ref_ptr _secondaryColors; osg::ref_ptr _fogCoords; std::vector > _texCoordArrays; std::vector > _attributesArrays; GeometryArrayList() {} GeometryArrayList(osg::Geometry& geometry) { _vertexes = geometry.getVertexArray(); unsigned int nbvertexes = _vertexes->getNumElements(); if (geometry.getNormalArray() && nbvertexes == geometry.getNormalArray()->getNumElements()) _normals = geometry.getNormalArray(); if (geometry.getColorArray() && nbvertexes == geometry.getColorArray()->getNumElements()) _colors = geometry.getColorArray(); if (geometry.getSecondaryColorArray() && nbvertexes == geometry.getSecondaryColorArray()->getNumElements()) _secondaryColors = geometry.getSecondaryColorArray(); if (geometry.getFogCoordArray() && nbvertexes == geometry.getFogCoordArray()->getNumElements()) _fogCoords = geometry.getFogCoordArray(); _texCoordArrays.resize(geometry.getNumTexCoordArrays()); for(unsigned int i=0;igetNumElements()) _texCoordArrays[i] = geometry.getTexCoordArray(i); _attributesArrays.resize(geometry.getNumVertexAttribArrays()); for(unsigned int i=0;igetNumElements()) _attributesArrays[i] = geometry.getVertexAttribArrayList()[i]; } void setNumElements(unsigned int nbElements) { if (_vertexes.valid()) ArraySetNumElements()(_vertexes.get(), nbElements); if (_normals.valid()) ArraySetNumElements()(_normals.get(), nbElements); if (_colors.valid()) ArraySetNumElements()(_colors.get(), nbElements); if (_secondaryColors.valid()) ArraySetNumElements()(_secondaryColors.get(), nbElements); if (_fogCoords.valid()) ArraySetNumElements()(_fogCoords.get(), nbElements); for (unsigned int i = 0; i < _texCoordArrays.size(); i++) if (_texCoordArrays[i].valid()) ArraySetNumElements()(_texCoordArrays[i].get(), nbElements); for (unsigned int i = 0; i < _attributesArrays.size(); i++) if (_attributesArrays[i].valid()) ArraySetNumElements()(_attributesArrays[i].get(), nbElements); } unsigned int append(unsigned int index, GeometryArrayList& dst) { if (_vertexes.valid()) ArrayAppendElement()(_vertexes.get(), index, dst._vertexes.get()); if (_normals.valid()) ArrayAppendElement()(_normals.get(), index, dst._normals.get()); if (_colors.valid()) ArrayAppendElement()(_colors.get(), index, dst._colors.get()); if (_secondaryColors.valid()) ArrayAppendElement()(_secondaryColors.get(), index, dst._secondaryColors.get()); if (_fogCoords.valid()) ArrayAppendElement()(_fogCoords.get(), index, dst._fogCoords.get()); for (unsigned int i = 0; i < _texCoordArrays.size(); i++) if (_texCoordArrays[i].valid()) ArrayAppendElement()(_texCoordArrays[i].get(), index, dst._texCoordArrays[i].get()); for (unsigned int i = 0; i < _attributesArrays.size(); i++) if (_attributesArrays[i].valid()) ArrayAppendElement()(_attributesArrays[i].get(), index, dst._attributesArrays[i].get()); return dst._vertexes->getNumElements()-1; } unsigned int append(const IndexList& indexes, GeometryArrayList& dst) { if (_vertexes.valid()) { ArrayIndexAppendVisitor append(indexes, dst._vertexes.get()); _vertexes->accept(append); } if (_normals.valid()) { ArrayIndexAppendVisitor append(indexes, dst._normals.get()); _normals->accept(append); } if (_colors.valid()) { ArrayIndexAppendVisitor append(indexes, dst._colors.get()); _colors->accept(append); } if (_secondaryColors.valid()) { ArrayIndexAppendVisitor append(indexes, dst._secondaryColors.get()); _secondaryColors->accept(append); } if (_fogCoords.valid()) { ArrayIndexAppendVisitor append(indexes, dst._fogCoords.get()); _fogCoords->accept(append); } for (unsigned int i = 0; i < _texCoordArrays.size(); i++) if (_texCoordArrays[i].valid()) { ArrayIndexAppendVisitor append(indexes, dst._texCoordArrays[i].get()); _texCoordArrays[i]->accept(append); } for (unsigned int i = 0; i < _attributesArrays.size(); i++) if (_attributesArrays[i].valid()) { ArrayIndexAppendVisitor append(indexes, dst._attributesArrays[i].get()); _attributesArrays[i]->accept(append); } return dst._vertexes->getNumElements()-1; } GeometryArrayList cloneType() const { GeometryArrayList array; if (_vertexes.valid()) array._vertexes = dynamic_cast(_vertexes->cloneType()); if (_normals.valid()) array._normals = dynamic_cast(_normals->cloneType()); if (_colors.valid()) array._colors = dynamic_cast(_colors->cloneType()); if (_secondaryColors.valid()) array._secondaryColors = dynamic_cast(_secondaryColors->cloneType()); if (_fogCoords.valid()) array._fogCoords = dynamic_cast(_fogCoords->cloneType()); array._texCoordArrays.resize(_texCoordArrays.size()); for (unsigned int i = 0; i < _texCoordArrays.size(); i++) { if (_texCoordArrays[i].valid()) array._texCoordArrays[i] = dynamic_cast(_texCoordArrays[i]->cloneType()); } array._attributesArrays.resize(_attributesArrays.size()); for (unsigned int i = 0; i < _attributesArrays.size(); i++) { if (_attributesArrays[i].valid()) array._attributesArrays[i] = dynamic_cast(_attributesArrays[i]->cloneType()); } return array; } unsigned int size() const { return _vertexes->getNumElements(); } void setToGeometry(osg::Geometry& geom) { if (_vertexes.valid()) geom.setVertexArray(_vertexes.get()); if (_normals.valid()) { geom.setNormalArray(_normals.get(), osg::Array::BIND_PER_VERTEX); } if (_colors.valid()) { geom.setColorArray(_colors.get(), osg::Array::BIND_PER_VERTEX); } if (_secondaryColors.valid()) { geom.setSecondaryColorArray(_secondaryColors.get(), osg::Array::BIND_PER_VERTEX); } if (_fogCoords.valid()) { geom.setFogCoordArray(_fogCoords.get(), osg::Array::BIND_PER_VERTEX); } for (unsigned int i = 0; i < _texCoordArrays.size(); ++i) { if (_texCoordArrays[i].valid()) { geom.setTexCoordArray(i, _texCoordArrays[i].get(), osg::Array::BIND_PER_VERTEX); } } for (unsigned int i = 0; i < _attributesArrays.size(); ++i) { if (_attributesArrays[i].valid()) { geom.setVertexAttribArray(i, _attributesArrays[i].get(), osg::Array::BIND_PER_VERTEX); } } } }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/StatLogger0000644000175000017500000000126713151044751024741 0ustar albertoalberto#ifndef STAT_LOGGER #define STAT_LOGGER #include #include class StatLogger { public: StatLogger(const std::string& label): _start(getTick()), _label(label) {} ~StatLogger() { _stop = getTick(); OSG_INFO << std::flush << "Info: " << _label << " timing: " << getElapsedSeconds() << "s" << std::endl << std::flush; } protected: osg::Timer_t _start, _stop; std::string _label; inline osg::Timer_t getTick() const { return osg::Timer::instance()->tick(); } inline double getElapsedSeconds() const { return osg::Timer::instance()->delta_s(_start, _stop); } }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/TriangleLinePointIndexFunctor0000644000175000017500000002007613151044751030605 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef TRIANGLE_LINE_POINT_INDEX_FUNCTOR #define TRIANGLE_LINE_POINT_INDEX_FUNCTOR #include #include template class TriangleLinePointIndexFunctor : public osg::PrimitiveIndexFunctor, public T { public: virtual void setVertexArray(unsigned int,const osg::Vec2*) {} virtual void setVertexArray(unsigned int ,const osg::Vec3* ) {} virtual void setVertexArray(unsigned int,const osg::Vec4* ) {} virtual void setVertexArray(unsigned int,const osg::Vec2d*) {} virtual void setVertexArray(unsigned int ,const osg::Vec3d* ) {} virtual void setVertexArray(unsigned int,const osg::Vec4d* ) {} virtual void begin(GLenum mode) { _modeCache = mode; _indexCache.clear(); } virtual void vertex(unsigned int vert) { _indexCache.push_back(vert); } virtual void end() { if (!_indexCache.empty()) { drawElements(_modeCache,_indexCache.size(),&_indexCache.front()); } } virtual void drawArrays(GLenum mode, GLint first, GLsizei count) { switch(mode) { case(GL_TRIANGLES): { unsigned int pos=first; for(GLsizei i = 2 ; i < count ; i += 3, pos += 3) { this->operator()(pos, pos + 1, pos + 2); } break; } case(GL_TRIANGLE_STRIP): { unsigned int pos = first; for(GLsizei i = 2 ; i < count ; ++ i, ++ pos) { if ((i%2)) this->operator()(pos, pos + 2, pos + 1); else this->operator()(pos, pos + 1, pos + 2); } break; } case(GL_QUADS): { unsigned int pos = first; for(GLsizei i = 3 ; i < count ; i += 4, pos += 4) { this->operator()(pos,pos + 1, pos + 2); this->operator()(pos,pos + 2, pos + 3); } break; } case(GL_QUAD_STRIP): { unsigned int pos = first; for(GLsizei i = 3 ; i < count ; i += 2, pos += 2) { this->operator()(pos, pos + 1,pos + 2); this->operator()(pos + 1,pos + 3,pos + 2); } break; } case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN case(GL_TRIANGLE_FAN): { unsigned int pos = first + 1; for(GLsizei i = 2 ; i < count ; ++ i, ++ pos) { this->operator()(first, pos, pos + 1); } break; } case(GL_LINES): { unsigned int pos = first; for(GLsizei i = 0 ; i < count ; i += 2, pos += 2) { this->operator()(pos, pos + 1); } break; } case(GL_LINE_STRIP): { unsigned int pos = first; for(GLsizei i = 0 ; i < count - 1 ; i += 1, pos += 1) { this->operator()(pos, pos + 1); } break; } case(GL_LINE_LOOP): { unsigned int pos = first; for(GLsizei i = 0 ; i < count - 1 ; i += 1, pos += 1) { this->operator()(pos, pos + 1); } this->operator()(pos, first); break; } case(GL_POINTS): { unsigned int pos=first; for(GLsizei i = 0 ; i < count ; ++ i) { this->operator()(pos + i); } break; } default: break; } } template void drawElements(GLenum mode, GLsizei count, const I* indices) { typedef I Index; typedef const I* IndexPointer; if (indices == 0 || count == 0) { return; } switch(mode) { case(GL_TRIANGLES): { IndexPointer ilast = &indices[count]; for(IndexPointer iptr = indices ; iptr < ilast ; iptr += 3) { this->operator()(*iptr, *(iptr + 1), *(iptr + 2)); } break; } case(GL_TRIANGLE_STRIP): { IndexPointer iptr = indices; for(GLsizei i = 2 ; i < count ; ++ i, ++ iptr) { if ((i%2)) this->operator()(*(iptr), *(iptr + 2), *(iptr + 1)); else this->operator()(*(iptr), *(iptr + 1), *(iptr + 2)); } break; } case(GL_QUADS): { IndexPointer iptr = indices; for(GLsizei i = 3 ; i < count ; i += 4, iptr += 4) { this->operator()(*(iptr), *(iptr + 1), *(iptr + 2)); this->operator()(*(iptr), *(iptr + 2), *(iptr + 3)); } break; } case(GL_QUAD_STRIP): { IndexPointer iptr = indices; for(GLsizei i = 3 ; i < count ; i += 2, iptr += 2) { this->operator()(*(iptr), *(iptr + 1), *(iptr + 2)); this->operator()(*(iptr + 1), *(iptr + 3), *(iptr + 2)); } break; } case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN case(GL_TRIANGLE_FAN): { IndexPointer iptr = indices; Index first = *iptr; ++iptr; for(GLsizei i = 2 ; i < count ; ++ i, ++ iptr) { this->operator()(first, *(iptr), *(iptr + 1)); } break; } case(GL_LINES): { const I* iptr = indices; for(GLsizei i = 0 ; i < count ; i += 2, iptr += 2) { this->operator()(*iptr, *(iptr + 1)); } break; } case(GL_LINE_STRIP): { const I* iptr = indices; for(GLsizei i = 0 ; i < count - 1 ; i += 1, iptr += 1) { this->operator()(*iptr, *(iptr + 1)); } break; } case(GL_LINE_LOOP): { const I* iptr = indices; I first = *iptr; for(GLsizei i = 0 ; i < count - 1 ; i += 1, iptr += 1) { this->operator()(*iptr, *(iptr + 1)); } this->operator()(*iptr, first); break; } case GL_POINTS: { IndexPointer ilast = &indices[count]; for(IndexPointer iptr = indices ; iptr < ilast ; iptr += 1) { this->operator()(*iptr); } break; } default: break; } } virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices) { drawElements(mode, count, indices); } virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) { drawElements(mode, count, indices); } virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) { drawElements(mode, count, indices); } GLenum _modeCache; std::vector _indexCache; std::vector _remap; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/DrawArrayVisitor0000644000175000017500000000733613151044751026145 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef DRAW_ARRAY_VISITOR #define DRAW_ARRAY_VISITOR #include "GeometryUniqueVisitor" #include "GeometryArray" class DrawArrayVisitor : public GeometryUniqueVisitor { public: DrawArrayVisitor(): GeometryUniqueVisitor("DrawArrayVisitor") {} void apply(osg::Geometry& geometry) { GeometryArrayList srcArrays(geometry); // clone but clear content osg::Geometry* newGeometry = new osg::Geometry; GeometryArrayList dst = srcArrays.cloneType(); for (unsigned int i = 0; i < geometry.getNumPrimitiveSets(); i++) { osg::PrimitiveSet* ps = geometry.getPrimitiveSet(i); switch (ps->getType()) { case osg::PrimitiveSet::DrawArraysPrimitiveType: { osg::DrawArrays* dw = dynamic_cast(ps); unsigned int start = dst.size(); osg::DrawArrays* ndw = new osg::DrawArrays(dw->getMode(), start, dw->getNumIndices()); newGeometry->getPrimitiveSetList().push_back(ndw); for ( unsigned int j = 0; j < dw->getNumIndices(); j++) { srcArrays.append(dw->getFirst()+j, dst); } } break; case osg::PrimitiveSet::DrawElementsUBytePrimitiveType: case osg::PrimitiveSet::DrawElementsUShortPrimitiveType: case osg::PrimitiveSet::DrawElementsUIntPrimitiveType: { osg::DrawElements* de = ps->getDrawElements(); unsigned int start = dst.size(); osg::DrawArrays* ndw = new osg::DrawArrays(de->getMode(), start, de->getNumIndices()); newGeometry->getPrimitiveSetList().push_back(ndw); for (unsigned int j = 0; j < de->getNumIndices(); j++) { unsigned int idx = de->getElement(j); srcArrays.append(idx, dst); } } break; case osg::PrimitiveSet::DrawArrayLengthsPrimitiveType: { osg::DrawArrayLengths* dal = dynamic_cast(ps); unsigned int start = dst.size(); unsigned int offset = dal->getFirst(); unsigned int totalDrawArraysVertexes = 0; for (unsigned int j = 0; j < dal->size(); j++) { totalDrawArraysVertexes += (*dal)[j]; } osg::DrawArrays* ndw = new osg::DrawArrays(dal->getMode(), start, totalDrawArraysVertexes); newGeometry->getPrimitiveSetList().push_back(ndw); for (unsigned int v = 0; v < totalDrawArraysVertexes; v++) { srcArrays.append(offset + v, dst); } } break; default: break; } } dst.setToGeometry(geometry); geometry.setPrimitiveSetList(newGeometry->getPrimitiveSetList()); setProcessed(&geometry); } }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/UnIndexMeshVisitor0000644000175000017500000000137013151044751026430 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef UNINDEX_MESH_VISITOR #define UNINDEX_MESH_VISITOR #include "GeometryUniqueVisitor" class UnIndexMeshVisitor : public GeometryUniqueVisitor { public: UnIndexMeshVisitor(): GeometryUniqueVisitor("UnIndexMeshVisitor") {} void apply(osg::Geometry& geom); }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/AnimationVisitor0000644000175000017500000000163513151044751026164 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef ANIMATION_VISITOR #define ANIMATION_VISITOR #include #include #include #include // the idea is to create true Geometry if skeleton with RigGeometry class AnimationVisitor : public osgUtil::UpdateVisitor { public: AnimationVisitor() { setFrameStamp(new osg::FrameStamp()); } }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/forsythtriangleorderoptimizer.h0000644000175000017500000000406513151044751031336 0ustar albertoalberto//----------------------------------------------------------------------------- // This is an implementation of Tom Forsyth's "Linear-Speed Vertex Cache // Optimization" algorithm as described here: // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html // // This code was authored and released into the public domain by // Adrian Stone (stone@gameangst.com). // // THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER // LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //----------------------------------------------------------------------------- #ifndef __FORSYTH_TRIANGLE_REORDER__ #define __FORSYTH_TRIANGLE_REORDER__ namespace Forsyth { //----------------------------------------------------------------------------- // OptimizeFaces //----------------------------------------------------------------------------- // Parameters: // indexList // input index list // indexCount // the number of indices in the list // vertexCount // the largest index value in indexList // newIndexList // a pointer to a preallocated buffer the same size as indexList to // hold the optimized index list // lruCacheSize // the size of the simulated post-transform cache (max:64) //----------------------------------------------------------------------------- void OptimizeFaces(const unsigned int* indexList, unsigned int indexCount, unsigned int vertexCount, unsigned int* newIndexList, unsigned int lruCacheSize); } // namespace Forsyth #endif // __FORSYTH_TRIANGLE_REORDER__ OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/forsythtriangleorderoptimizer.cpp0000644000175000017500000003315513151044751031673 0ustar albertoalberto//----------------------------------------------------------------------------- // This is an implementation of Tom Forsyth's "Linear-Speed Vertex Cache // Optimization" algorithm as described here: // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html // // This code was authored and released into the public domain by // Adrian Stone (stone@gameangst.com). // // THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER // LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //----------------------------------------------------------------------------- #include #include #include #include #include namespace Forsyth { //----------------------------------------------------------------------------- // OptimizeFaces //----------------------------------------------------------------------------- // Parameters: // indexList // input index list // indexCount // the number of indices in the list // vertexCount // the largest index value in indexList // newIndexList // a pointer to a preallocated buffer the same size as indexList to // hold the optimized index list // lruCacheSize // the size of the simulated post-transform cache (max:64) //----------------------------------------------------------------------------- void OptimizeFaces(const unsigned int* indexList, unsigned int indexCount, unsigned int vertexCount, unsigned int* newIndexList, unsigned int lruCacheSize); namespace { #if 0 // code for computing vertex score was taken, as much as possible // directly from the original publication. float ComputeVertexCacheScore(int cachePosition, int vertexCacheSize) { const float FindVertexScore_CacheDecayPower = 1.5f; const float FindVertexScore_LastTriScore = 0.75f; float score = 0.0f; if ( cachePosition < 0 ) { // Vertex is not in FIFO cache - no score. } else { if ( cachePosition < 3 ) { // This vertex was used in the last triangle, // so it has a fixed score, whichever of the three // it's in. Otherwise, you can get very different // answers depending on whether you add // the triangle 1,2,3 or 3,1,2 - which is silly. score = FindVertexScore_LastTriScore; } else { assert ( cachePosition < vertexCacheSize ); // Points for being high in the cache. const float scaler = 1.0f / ( vertexCacheSize - 3 ); score = 1.0f - ( cachePosition - 3 ) * scaler; score = powf ( score, FindVertexScore_CacheDecayPower ); } } return score; } #endif float ComputeVertexValenceScore(unsigned int numActiveFaces) { const float FindVertexScore_ValenceBoostScale = 2.0f; const float FindVertexScore_ValenceBoostPower = 0.5f; float score = 0.f; // Bonus points for having a low number of tris still to // use the vert, so we get rid of lone verts quickly. float valenceBoost = powf ( static_cast(numActiveFaces), -FindVertexScore_ValenceBoostPower ); score += FindVertexScore_ValenceBoostScale * valenceBoost; return score; } const int kMaxVertexCacheSize = 64; const unsigned int kMaxPrecomputedVertexValenceScores = 64; float s_vertexCacheScores[kMaxVertexCacheSize+1][kMaxVertexCacheSize]; float s_vertexValenceScores[kMaxPrecomputedVertexValenceScores]; #if 0 bool ComputeVertexScores() { for (int cacheSize=0; cacheSize<=kMaxVertexCacheSize; ++cacheSize) { for (int cachePos=0; cachePos vertexDataList; vertexDataList.resize(vertexCount); // compute face count per vertex for (unsigned int i=0; i activeFaceList; const unsigned int kEvictedCacheIndex = std::numeric_limits::max(); { // allocate face list per vertex unsigned int curActiveFaceListPos = 0; for (unsigned int i=0; i processedFaceList; processedFaceList.resize(indexCount); unsigned int vertexCacheBuffer[(kMaxVertexCacheSize+3)*2]; unsigned int* cache0 = vertexCacheBuffer; unsigned int* cache1 = vertexCacheBuffer+(kMaxVertexCacheSize+3); unsigned int entriesInCache0 = 0; unsigned int bestFace = 0; float bestScore = -1.f; const float maxValenceScore = FindVertexScore(1, kEvictedCacheIndex, lruCacheSize) * 3.f; for (unsigned int i = 0; i < indexCount; i += 3) { if (bestScore < 0.f) { // no verts in the cache are used by any unprocessed faces so // search all unprocessed faces for a new starting point for (unsigned int j = 0; j < indexCount; j += 3) { if (processedFaceList[j] == 0) { unsigned int face = j; float faceScore = 0.f; for (unsigned int k=0; k<3; ++k) { unsigned int index = indexList[face+k]; OptimizeVertexData& vertexData = vertexDataList[index]; assert(vertexData.activeFaceListSize > 0); assert(vertexData.cachePos0 >= lruCacheSize); faceScore += vertexData.score; } if (faceScore > bestScore) { bestScore = faceScore; bestFace = face; assert(bestScore <= maxValenceScore); if (bestScore >= maxValenceScore) { break; } } } } assert(bestScore >= 0.f); } processedFaceList[bestFace] = 1; unsigned int entriesInCache1 = 0; // add bestFace to LRU cache and to newIndexList for (unsigned int v = 0; v < 3; ++v) { unsigned int index = indexList[bestFace+v]; newIndexList[i+v] = index; OptimizeVertexData& vertexData = vertexDataList[index]; if (vertexData.cachePos1 >= entriesInCache1) { vertexData.cachePos1 = entriesInCache1; cache1[entriesInCache1++] = index; if (vertexData.activeFaceListSize == 1) { --vertexData.activeFaceListSize; continue; } } assert(vertexData.activeFaceListSize > 0); unsigned int* begin = &activeFaceList[vertexData.activeFaceListStart]; unsigned int* end = &activeFaceList[vertexData.activeFaceListStart + vertexData.activeFaceListSize]; unsigned int* it = std::find(begin, end, bestFace); assert(it != end); std::swap(*it, *(end-1)); --vertexData.activeFaceListSize; vertexData.score = FindVertexScore(vertexData.activeFaceListSize, vertexData.cachePos1, lruCacheSize); } // move the rest of the old verts in the cache down and compute their new scores for (unsigned int c0 = 0; c0 < entriesInCache0; ++c0) { unsigned int index = cache0[c0]; OptimizeVertexData& vertexData = vertexDataList[index]; if (vertexData.cachePos1 >= entriesInCache1) { vertexData.cachePos1 = entriesInCache1; cache1[entriesInCache1++] = index; vertexData.score = FindVertexScore(vertexData.activeFaceListSize, vertexData.cachePos1, lruCacheSize); } } // find the best scoring triangle in the current cache (including up to 3 that were just evicted) bestScore = -1.f; for (unsigned int c1 = 0; c1 < entriesInCache1; ++c1) { unsigned int index = cache1[c1]; OptimizeVertexData& vertexData = vertexDataList[index]; vertexData.cachePos0 = vertexData.cachePos1; vertexData.cachePos1 = kEvictedCacheIndex; for (unsigned int j=0; j bestScore) { bestScore = faceScore; bestFace = face; } } } std::swap(cache0, cache1); entriesInCache0 = std::min(entriesInCache1, lruCacheSize); } } } // namespace Forsyth OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/PointIndexFunctor0000644000175000017500000000665313151044751026314 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef POINT_INDEX_FUNCTOR_H #define POINT_INDEX_FUNCTOR_H #include #include template class PointIndexFunctor : public osg::PrimitiveIndexFunctor, public T { public: virtual void setVertexArray(unsigned int,const osg::Vec2*) { } virtual void setVertexArray(unsigned int ,const osg::Vec3* ) { } virtual void setVertexArray(unsigned int,const osg::Vec4* ) { } virtual void setVertexArray(unsigned int,const osg::Vec2d*) { } virtual void setVertexArray(unsigned int ,const osg::Vec3d* ) { } virtual void setVertexArray(unsigned int,const osg::Vec4d* ) { } virtual void begin(GLenum mode) { _modeCache = mode; _indexCache.clear(); } virtual void vertex(unsigned int vert) { _indexCache.push_back(vert); } virtual void end() { if (!_indexCache.empty()) { drawElements(_modeCache,_indexCache.size(),&_indexCache.front()); } } virtual void drawArrays(GLenum mode,GLint first,GLsizei count) { switch(mode) { case(GL_POINTS): { unsigned int pos=first; for(GLsizei i=0;ioperator()(pos+i); } break; default: // can't be converted into to triangles. break; } } virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) { if (indices==0 || count==0) return; typedef GLubyte Index; typedef const Index* IndexPointer; switch(mode) { case (GL_POINTS): { IndexPointer ilast = &indices[count]; for(IndexPointer iptr=indices;iptroperator()(*iptr); } break; default: break; } } virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) { if (indices==0 || count==0) return; typedef GLushort Index; typedef const Index* IndexPointer; switch(mode) { case (GL_POINTS): { IndexPointer ilast = &indices[count]; for(IndexPointer iptr=indices;iptroperator()(*iptr); } break; default: break; } } virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) { if (indices==0 || count==0) return; typedef GLuint Index; typedef const Index* IndexPointer; switch(mode) { case (GL_POINTS): { IndexPointer ilast = &indices[count]; for(IndexPointer iptr=indices;iptroperator()(*iptr); } break; default: break; } } GLenum _modeCache; std::vector _indexCache; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/WireframeVisitor0000644000175000017500000000475513151044751026174 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef WIREFRAME_VISITOR #define WIREFRAME_VISITOR #include #include #include #include #include "GeometryUniqueVisitor" #include "PrimitiveIndexors" class WireframeVisitor : public GeometryUniqueVisitor { public: WireframeVisitor(bool inlined=false): GeometryUniqueVisitor("WireframeVisitor"), _inlined(inlined) {} void apply(osg::Node& node) { handleStateSet(node); traverse(node); } void apply(osg::Geode& geode) { handleStateSet(geode); for (unsigned int i = 0; i < geode.getNumDrawables(); i++) { apply(*geode.getDrawable(i)); } } void apply(osg::Drawable& drawable) { osg::Geometry* geometry = drawable.asGeometry(); if (!geometry) { return; } apply(*geometry); } void apply(osg::Geometry& geometry) { if(_processed.find(&geometry) == _processed.end()) { const unsigned int nbSourcePrimitives = geometry.getNumPrimitiveSets(); for(unsigned int i = 0 ; i < nbSourcePrimitives ; ++ i) { osg::PrimitiveSet* primitive = geometry.getPrimitiveSet(i); EdgeIndexor edges; primitive->accept(edges); if(!edges._indices.empty()) { osg::DrawElementsUInt* wireframe = new osg::DrawElementsUInt(osg::PrimitiveSet::LINES, edges._indices.begin(), edges._indices.end()); wireframe->setUserValue("wireframe", true); geometry.getPrimitiveSetList().push_back(wireframe); } } _processed.insert(&geometry); } } void handleStateSet(osg::Node& node) { if(!_inlined) { node.setStateSet(0); } } std::set _processed; bool _inlined; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/GeometrySplitterVisitor0000644000175000017500000003514613151044751027573 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef GEOMETRY_SPLITTER_VISITOR #define GEOMETRY_SPLITTER_VISITOR #include #include #include #include #include #include #include #include "GeometryArray" #include "GeometryUniqueVisitor" #include "glesUtil" class GeometryIndexSplitter { public: typedef std::vector > GeometryList; GeometryIndexSplitter(unsigned int maxIndex, bool disablePostTransform): _maxIndexToSplit(maxIndex), _disablePostTransform(disablePostTransform) {} bool split(osg::Geometry& geometry) { if(!hasValidPrimitives(geometry) || !needToSplit(geometry)) { if(!_disablePostTransform) { // optimize cache for rendering glesUtil::VertexCacheVisitor posttransform; posttransform.optimizeVertices(geometry); } _geometryList.push_back(&geometry); // remap geometry to itself return false; } // keep bounding box data as user value if needed in subsequent processing attachBufferBoundingBox(geometry); // first optimize primitives indexing { if(!_disablePostTransform) { // post-transform for better locality glesUtil::VertexCacheVisitor posttransform; posttransform.optimizeVertices(geometry); } // pre-transform to reindex correctly glesUtil::VertexAccessOrderVisitor pretransform; pretransform.optimizeOrder(geometry); } // Clone geometry as we will modify vertex arrays and primitives // To avoid issues with shared buffers, arrays & primitives should be // deep cloned. // As UserValues might be changed on a per-geometry basis afterwards, we // also deep clone userdata // We do *not* want to clone statesets as they reference a UniqueID that // should be unique (see #83056464). osg::ref_ptr processing = osg::clone(&geometry, osg::CopyOp::DEEP_COPY_ARRAYS | osg::CopyOp::DEEP_COPY_PRIMITIVES | osg::CopyOp::DEEP_COPY_USERDATA); osg::ref_ptr reported; while (true) { reported = doSplit(*processing); // reduce vertex array if needed if(processing && processing->getNumPrimitiveSets()) { GeometryArrayList arrayList(*processing); arrayList.setNumElements(osg::minimum(arrayList.size(), _maxIndexToSplit + 1)); _geometryList.push_back(processing); } if (!reported.valid()) { break; } else { processing = reported; reported = 0; // re order index elements glesUtil::VertexAccessOrderVisitor preTransform; preTransform.optimizeOrder(*processing); } } osg::notify(osg::NOTICE) << "geometry " << &geometry << " " << geometry.getName() << " vertexes (" << geometry.getVertexArray()->getNumElements() << ") has DrawElements index > " << _maxIndexToSplit << ", splitted to " << _geometryList.size() << " geometry" << std::endl; return true; } protected: bool hasValidPrimitives(osg::Geometry& geometry) const { for (unsigned int i = 0; i < geometry.getNumPrimitiveSets(); ++ i) { osg::PrimitiveSet* primitive = geometry.getPrimitiveSet(i); if (primitive) { if (!primitive->getDrawElements()) { osg::notify(osg::INFO) << "can't split Geometry " << geometry.getName() << " (" << &geometry << ") contains non indexed primitives" << std::endl; return false; } switch (primitive->getMode()) { case osg::PrimitiveSet::TRIANGLES: case osg::PrimitiveSet::LINES: case osg::PrimitiveSet::POINTS: break; default: osg::notify(osg::FATAL) << "can't split Geometry " << geometry.getName() << " (" << &geometry << ") contains non point/line/triangle primitives" << std::endl; return false; break; } } } return true; } bool needToSplit(const osg::Geometry& geometry) const { for(unsigned int i = 0; i < geometry.getNumPrimitiveSets(); ++ i) { const osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements(); if (needToSplit(*primitive)) { return true; } } return false; } bool needToSplit(const osg::DrawElements& primitive) const { for(unsigned int j = 0; j < primitive.getNumIndices(); j++) { if (primitive.index(j) > _maxIndexToSplit){ return true; } } return false; } void attachBufferBoundingBox(osg::Geometry& geometry) const { // positions setBufferBoundingBox(dynamic_cast(geometry.getVertexArray())); // uvs for(unsigned int i = 0 ; i < geometry.getNumTexCoordArrays() ; ++ i) { setBufferBoundingBox(dynamic_cast(geometry.getTexCoordArray(i))); } } template void setBufferBoundingBox(T* buffer) const { if(!buffer) return; typename T::ElementDataType bbl; typename T::ElementDataType ufr; const unsigned int dimension = buffer->getDataSize(); if(buffer->getNumElements()) { for(unsigned int i = 0 ; i < dimension ; ++i) { bbl[i] = ufr[i] = (*buffer->begin())[i]; } for(typename T::const_iterator it = buffer->begin() + 1 ; it != buffer->end() ; ++ it) { for(unsigned int i = 0 ; i < dimension ; ++ i) { bbl[i] = std::min(bbl[i], (*it)[i]); ufr[i] = std::max(ufr[i], (*it)[i]); } } buffer->setUserValue("bbl", bbl); buffer->setUserValue("ufr", ufr); } } osg::Geometry* doSplit(osg::Geometry& geometry) const { osg::Geometry::PrimitiveSetList geomPrimitives; osg::Geometry::PrimitiveSetList wirePrimitives; osg::Geometry::PrimitiveSetList reportedPrimitives; std::vector< osg::ref_ptr > primitivesToFix; osg::Geometry::PrimitiveSetList& primitives = geometry.getPrimitiveSetList(); std::set validIndices; osg::ref_ptr reportGeometry; for (unsigned int i = 0; i < primitives.size(); i++) { osg::DrawElements *primitive = primitives[i]->getDrawElements(); bool isWireframe = false; if(primitive->getUserValue("wireframe", isWireframe)) { wirePrimitives.push_back(primitive); } else if (needToSplit(*primitive)) { primitivesToFix.push_back(primitive); } else { geomPrimitives.push_back(primitive); setValidIndices(validIndices, primitive); } } if (!primitivesToFix.empty()) { // filter all indices > _maxIndexValue in primitives for (unsigned int i = 0; i < primitivesToFix.size(); i++) { osg::DrawElements* source = primitivesToFix[i].get(); osg::DrawElements* large = removeLargeIndices(dynamic_cast(source)); reportedPrimitives.push_back(large); geomPrimitives.push_back(source); setValidIndices(validIndices, source); } } // keep wireframe data associated to the current solid geometry extractWireframePrimitive(wirePrimitives, validIndices, geomPrimitives, reportedPrimitives); geometry.setPrimitiveSetList(geomPrimitives); if (!reportedPrimitives.empty()) { reportGeometry = osg::clone(&geometry, osg::CopyOp::DEEP_COPY_ARRAYS | osg::CopyOp::DEEP_COPY_USERDATA); reportGeometry->setPrimitiveSetList(reportedPrimitives); return reportGeometry.release(); } return 0; } void setValidIndices(std::set& indices, const osg::DrawElements* primitive) const { for(unsigned int j = 0 ; j < primitive->getNumIndices() ; ++ j) { indices.insert(primitive->index(j)); } } osg::DrawElements* removeLargeIndices(osg::DrawElementsUInt* source) const { osg::DrawElementsUInt* large = new osg::DrawElementsUInt(source->getMode()); unsigned int primitive_size = 0; switch(source->getMode()) { case osg::PrimitiveSet::POINTS: primitive_size = 1; break; case osg::PrimitiveSet::LINES: primitive_size = 2; break; case osg::PrimitiveSet::TRIANGLES: primitive_size = 3; break; } for (int id = source->getNumPrimitives() - 1; id >= 0; -- id) { const unsigned int arrayIndex = id * primitive_size; for(unsigned int i = 0 ; i < primitive_size ; ++ i) { if(source->index(arrayIndex + i) > _maxIndexToSplit) { // add primitive in the large DrawElements for(unsigned int j = 0 ; j < primitive_size ; ++ j) { large->addElement(source->index(arrayIndex + j)); } // remove primitive from source DrawElements for(int j = primitive_size - 1 ; j >= 0 ; -- j) { source->erase(source->begin() + arrayIndex + j); } break; // skip to next primitive } } } return large; } // keep wireframe data associated to the solid geometry void extractWireframePrimitive(osg::Geometry::PrimitiveSetList& lines, const std::set& indices, osg::Geometry::PrimitiveSetList& primitives, osg::Geometry::PrimitiveSetList& reported) const { if(indices.empty()) { return; } for(unsigned int i = 0 ; i < lines.size() ; ++ i) { const osg::DrawElementsUInt* line = dynamic_cast(lines[i].get()); if(!line || line->getMode() != osg::PrimitiveSet::LINES) { osg::notify(osg::INFO) << "Primitive with bad mode flagged as wireframe. Skipping." << std::endl; } osg::ref_ptr small = new osg::DrawElementsUInt(osg::PrimitiveSet::LINES); osg::ref_ptr large = new osg::DrawElementsUInt(osg::PrimitiveSet::LINES); for (unsigned int id = 0 ; id < line->getNumPrimitives() ; ++ id) { unsigned int arrayIndex = id * 2; unsigned int a = line->index(arrayIndex), b = line->index(arrayIndex + 1); if(indices.find(a) != indices.end() && indices.find(b) != indices.end()) { small->addElement(a); small->addElement(b); } else { large->addElement(a); large->addElement(b); } } if(small->size()) { small->setUserValue("wireframe", true); primitives.push_back(small); } if(large->size()) { large->setUserValue("wireframe", true); reported.push_back(large); } } } public: const unsigned int _maxIndexToSplit; bool _disablePostTransform; GeometryList _geometryList; }; class GeometrySplitterVisitor : public GeometryUniqueVisitor { public: typedef std::vector< osg::ref_ptr > GeometryList; GeometrySplitterVisitor(unsigned int maxIndexValue = 65535, bool disablePostTransform=false): GeometryUniqueVisitor("GeometrySplitterVisitor"), _maxIndexValue(maxIndexValue), _disablePostTransform(disablePostTransform) {} void apply(osg::Geode& geode) { GeometryUniqueVisitor::apply(geode); GeometryList remapped; for(unsigned int i = 0 ; i < geode.getNumDrawables() ; ++ i) { osg::Geometry* geometry = geode.getDrawable(i)->asGeometry(); if(geometry) { std::map::iterator lookup = _split.find(geometry); if(lookup != _split.end() && !lookup->second.empty()) { remapped.insert(remapped.end(), lookup->second.begin(), lookup->second.end()); } } } // remove all drawables geode.removeDrawables(0, geode.getNumDrawables()); for(unsigned int i = 0 ; i < remapped.size() ; ++ i) { geode.addDrawable(remapped[i].get()); } } void apply(osg::Geometry& geometry) { GeometryIndexSplitter splitter(_maxIndexValue, _disablePostTransform); splitter.split(geometry); setProcessed(&geometry, splitter._geometryList); } protected: bool isProcessed(osg::Geometry* node) { return _split.find(node) != _split.end(); } void setProcessed(osg::Geometry* node, const GeometryList& list) { _split.insert(std::pair(node, GeometryList(list))); } unsigned int _maxIndexValue; std::map _split; bool _disablePostTransform; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/ReaderWriterGLES.cpp0000644000175000017500000002352713151044751026524 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include "UnIndexMeshVisitor" #include "OpenGLESGeometryOptimizer" using namespace osg; class ReaderWriterGLES : public osgDB::ReaderWriter { public: struct OptionsStruct { std::string enableWireframe; bool generateTangentSpace; int tangentSpaceTextureUnit; bool disableTriStrip; bool disableMergeTriStrip; bool disablePreTransform; bool disablePostTransform; unsigned int triStripCacheSize; unsigned int triStripMinSize; bool useDrawArray; bool disableIndex; unsigned int maxIndexValue; OptionsStruct() { enableWireframe = ""; generateTangentSpace = false; tangentSpaceTextureUnit = 0; disableTriStrip = false; disableMergeTriStrip = false; disablePreTransform = false; disablePostTransform = false; triStripCacheSize = 16; triStripMinSize = 2; useDrawArray = false; disableIndex = false; maxIndexValue = 0; } }; ReaderWriterGLES() { supportsExtension("gles","OpenGL ES optimized format"); supportsOption("enableWireframe[=inline]","create a wireframe geometry for each triangles geometry. The wire geometry will be stored along the solid geometry if 'inline' is specified."); supportsOption("generateTangentSpace","Build tangent space to each geometry"); supportsOption("tangentSpaceTextureUnit=","Specify on which texture unit normal map is"); supportsOption("triStripCacheSize=","set the cache size when doing tristrip"); supportsOption("triStripMinSize=","set the minimum accepted length for a strip"); supportsOption("disableMergeTriStrip","disable the merge of all tristrip into one"); supportsOption("disableTriStrip","disable generation of tristrip"); supportsOption("disablePreTransform","disable pre-transform of geometries after split"); supportsOption("disablePostTransform","disable post-transform of geometries (called during geometry splitting)"); supportsOption("useDrawArray","prefer drawArray instead of drawelement with split of geometry"); supportsOption("disableIndex","Do not index the geometry"); supportsOption("maxIndexValue=","set the maximum index value (first index is 0)"); } virtual const char* className() const { return "GLES Optimizer"; } virtual osg::Node* optimizeModel(const Node& node, const OptionsStruct& options) const { osg::Node* model = osg::clone(&node); if (options.disableIndex) { UnIndexMeshVisitor unindex; model->accept(unindex); } else { OpenGLESGeometryOptimizer optimizer; optimizer.setUseDrawArray(options.useDrawArray); optimizer.setTripStripCacheSize(options.triStripCacheSize); optimizer.setTripStripMinSize(options.triStripMinSize); optimizer.setDisableTriStrip(options.disableTriStrip); optimizer.setDisableMergeTriStrip(options.disableMergeTriStrip); optimizer.setDisablePreTransform(options.disablePreTransform); optimizer.setDisablePostTransform(options.disablePostTransform); optimizer.setWireframe(options.enableWireframe); if (options.generateTangentSpace) { optimizer.setTexCoordChannelForTangentSpace(options.tangentSpaceTextureUnit); } if(options.maxIndexValue) { optimizer.setMaxIndexValue(options.maxIndexValue); } model = optimizer.optimize(*model); } return model; } virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(fileName); if( !acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED; OSG_INFO << "ReaderWriterGLES( \"" << fileName << "\" )" << std::endl; // strip the pseudo-loader extension std::string realName = osgDB::getNameLessExtension( fileName ); if (realName.empty()) return ReadResult::FILE_NOT_HANDLED; // recursively load the subfile. osg::ref_ptr node = osgDB::readRefNodeFile( realName, options ); if( !node ) { // propagate the read failure upwards OSG_WARN << "Subfile \"" << realName << "\" could not be loaded" << std::endl; return ReadResult::FILE_NOT_HANDLED; } OptionsStruct _options; _options = parseOptions(options); node = optimizeModel(*node, _options); return node.release(); } virtual osgDB::ReaderWriter::WriteResult writeNode(const Node& node, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; std::string realFileName = osgDB::getNameLessExtension(fileName); if(realFileName.empty()) return WriteResult::FILE_NOT_HANDLED; // gles optimization OptionsStruct _options; _options = parseOptions(options); ref_ptr optimizedNode = optimizeModel(node, _options); // forward writing to next plugin ref_ptr rw = getReaderWriter(realFileName); if(rw) { return rw->writeNode(*optimizedNode, realFileName, options); } else { return WriteResult::ERROR_IN_WRITING_FILE; } } ReaderWriterGLES::OptionsStruct parseOptions(const osgDB::ReaderWriter::Options* options) const { OptionsStruct localOptions; if (options) { osg::notify(NOTICE) << "options " << options->getOptionString() << std::endl; std::istringstream iss(options->getOptionString()); std::string opt; while (iss >> opt) { // split opt into pre= and post= std::string pre_equals; std::string post_equals; size_t found = opt.find("="); if(found!=std::string::npos) { pre_equals = opt.substr(0,found); post_equals = opt.substr(found+1); } else { pre_equals = opt; } if (pre_equals == "enableWireframe") { if(post_equals == "inline") { localOptions.enableWireframe = "inline"; } else { localOptions.enableWireframe = "outline"; } } if (pre_equals == "useDrawArray") { localOptions.useDrawArray = true; } if (pre_equals == "disableMergeTriStrip") { localOptions.disableMergeTriStrip = true; } if (pre_equals == "disablePreTransform") { localOptions.disablePreTransform = true; } if (pre_equals == "disablePostTransform") { localOptions.disablePostTransform = true; } if (pre_equals == "disableTriStrip") { localOptions.disableTriStrip = true; } if (pre_equals == "generateTangentSpace") { localOptions.generateTangentSpace = true; } if (pre_equals == "disableIndex") { localOptions.disableIndex = true; } if (post_equals.length() > 0) { if (pre_equals == "tangentSpaceTextureUnit") { localOptions.tangentSpaceTextureUnit = atoi(post_equals.c_str()); } if (pre_equals == "triStripCacheSize") { localOptions.triStripCacheSize = atoi(post_equals.c_str()); } if (pre_equals == "triStripMinSize") { localOptions.triStripMinSize = atoi(post_equals.c_str()); } if (pre_equals == "maxIndexValue") { localOptions.maxIndexValue = atoi(post_equals.c_str()); } } } } return localOptions; } protected: ReaderWriter* getReaderWriter(const std::string& fileName) const { ref_ptr registry = osgDB::Registry::instance(); std::string ext = osgDB::getLowerCaseFileExtension(fileName); return registry->getReaderWriterForExtension(ext); } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(gles, ReaderWriterGLES) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/PrimitiveIndexors0000644000175000017500000000530613151044751026350 0ustar albertoalberto#ifndef PRIMITIVE_OPERATORS_H #define PRIMITIVE_OPERATORS_H #include #include #include #include "TriangleLinePointIndexFunctor" #include "EdgeIndexFunctor" #include "LineIndexFunctor" #include "PointIndexFunctor" typedef std::vector IndexList; // Construct an index list of triangles for DrawElements for any input // primitives. struct IndexOperator { unsigned int _maxIndex; IndexList _remapping; IndexList _indices; IndexOperator() : _maxIndex(0) {} inline unsigned int index(unsigned int v) { if(_remapping.empty()) { return v; } else { return _remapping[v]; } } // triangles inline void operator()(unsigned int p1, unsigned int p2, unsigned int p3) { if(!valid(p1, p2, p3)) { return; } if (_remapping.empty()) { _indices.push_back(p1); _indices.push_back(p2); _indices.push_back(p3); } else { _indices.push_back(_remapping[p1]); _indices.push_back(_remapping[p2]); _indices.push_back(_remapping[p3]); } } // edges inline void operator()(unsigned int p1, unsigned int p2) { if(!valid(p1, p2)) { return; } if (_remapping.empty()) { _indices.push_back(p1); _indices.push_back(p2); } else { _indices.push_back(_remapping[p1]); _indices.push_back(_remapping[p2]); } } // points inline void operator()(unsigned int p1) { if(!valid(p1)) { return; } if (_remapping.empty()) { _indices.push_back(p1); } else { _indices.push_back(_remapping[p1]); } } // filter primitives referencing bad indices inline bool valid(unsigned int v1, unsigned int v2, unsigned int v3) { if(_maxIndex) { return (v1 < _maxIndex && v2 < _maxIndex && v3 < _maxIndex); } return true; } inline bool valid(unsigned int v1, unsigned int v2) { if(_maxIndex) { return (v1 < _maxIndex && v2 < _maxIndex); } return true; } inline bool valid(unsigned int v1) { if(_maxIndex) { return (v1 < _maxIndex); } return true; } }; typedef osg::TriangleIndexFunctor TriangleIndexor; typedef EdgeIndexFunctor EdgeIndexor; typedef LineIndexFunctor LineIndexor; // indexes only primitives in LINES, LINE_STRIP, LINE_LOOP mode typedef PointIndexFunctor PointIndexor; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/LineIndexFunctor0000644000175000017500000001132113151044751026076 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef LINE_INDEX_FUNCTOR_H #define LINE_INDEX_FUNCTOR_H #include #include #include #include class Line { public: Line(unsigned int a, unsigned int b) { _a = std::min(a, b); _b = std::max(a, b); } bool operator<(const Line& e) { return _a < e._a || (_a == e._a && _b < e._b); } unsigned int _a, _b; }; struct LineCompare { bool operator()(const Line& lhs, const Line& rhs) const { return lhs._a < rhs._a || (lhs._a == rhs._a && lhs._b < rhs._b); } }; template class LineIndexFunctor : public osg::PrimitiveIndexFunctor, public T { public: virtual void setVertexArray(unsigned int,const osg::Vec2*) {} virtual void setVertexArray(unsigned int ,const osg::Vec3* ) {} virtual void setVertexArray(unsigned int,const osg::Vec4* ) {} virtual void setVertexArray(unsigned int,const osg::Vec2d*) {} virtual void setVertexArray(unsigned int ,const osg::Vec3d* ) {} virtual void setVertexArray(unsigned int,const osg::Vec4d* ) {} virtual void begin(GLenum mode) { _modeCache = mode; _indexCache.clear(); } virtual void vertex(unsigned int vert) { _indexCache.push_back(vert); } virtual void end() { if (!_indexCache.empty()) { drawElements(_modeCache, _indexCache.size(), &_indexCache.front()); } } virtual void drawArrays(GLenum mode, GLint first, GLsizei count) { switch(mode) { case(GL_LINES): { unsigned int pos = first; for(GLsizei i = 0 ; i < count ; i += 2, pos += 2) { line(pos, pos + 1); } } break; case(GL_LINE_STRIP): { unsigned int pos = first; for(GLsizei i = 0 ; i < count - 1 ; i += 1, pos += 1) { line(pos, pos + 1); } } break; case(GL_LINE_LOOP): { unsigned int pos = first; for(GLsizei i = 0 ; i < count - 1 ; i += 1, pos += 1) { line(pos, pos + 1); } line(pos, first); } break; default: // not a line break; } } template void drawElements(GLenum mode, GLsizei count, const I* indices) { if (indices == 0 || count == 0) return; switch(mode) { case(GL_LINES): { const I* iptr = indices; for(GLsizei i = 0 ; i < count ; i += 2, iptr += 2) { line(*iptr, *(iptr+1)); } } break; case(GL_LINE_STRIP): { const I* iptr = indices; for(GLsizei i = 0 ; i < count - 1 ; i += 1, iptr += 1) { line(*iptr, *(iptr+1)); } } break; case(GL_LINE_LOOP): { const I* iptr = indices; I first = *iptr; for(GLsizei i = 0 ; i < count - 1 ; i += 1, iptr += 1) { line(*iptr, *(iptr+1)); } line(*iptr, first); } break; default: // not a line break; } } virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices) { drawElements(mode, count, indices); } virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) { drawElements(mode, count, indices); } virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) { drawElements(mode, count, indices); } void line(unsigned int a, unsigned int b) { Line e(T::index(a), T::index(b)); // use remapped indices to deduplicate lines if(_lineCache.find(e) == _lineCache.end()) { this->operator()(a, b); _lineCache.insert(e); } } GLenum _modeCache; std::vector _indexCache; std::set _lineCache; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/glesUtil0000644000175000017500000005053213151044751024455 0ustar albertoalberto#ifndef GLES_UTIL #define GLES_UTIL #include #include #include #include #include #include #include #include #include "TriangleLinePointIndexFunctor" #include "StatLogger" #include "forsythtriangleorderoptimizer.h" namespace glesUtil { using namespace std; using namespace osg; typedef std::vector IndexList; /////////// Post-transform // A list of triangles that use a vertex is associated with the Vertex // structure in another array. struct Vertex { int trisUsing; size_t triList; // index to start of triangle storage Vertex() : trisUsing(0), triList(0) { } }; typedef vector VertexList; struct Triangle { unsigned verts[3]; }; typedef vector TriangleList; struct TriangleCounterOperator { VertexList* vertices; int triangleCount; TriangleCounterOperator() : vertices(0), triangleCount(0) {} void doVertex(unsigned p) { if (vertices->size() <= p) vertices->resize(p + 1); (*vertices)[p].trisUsing++; } void operator() (unsigned int p1, unsigned int p2, unsigned int p3) { if (p1 == p2 || p2 == p3 || p1 == p3) return; doVertex(p1); doVertex(p2); doVertex(p3); triangleCount++; } }; struct TriangleCounter : public TriangleIndexFunctor { TriangleCounter(vector* vertices_) { vertices = vertices_; } }; // Initialize the vertex triangle lists and the triangle data structures struct TriangleAddOperator { VertexList* vertices; TriangleList* triangles; int triIdx; TriangleAddOperator() : vertices(0), triIdx(0) {} void operator() (unsigned int p1, unsigned int p2, unsigned int p3) { if (p1 == p2 || p2 == p3 || p1 == p3) return; (*triangles)[triIdx].verts[0] = p1; (*triangles)[triIdx].verts[1] = p2; (*triangles)[triIdx].verts[2] = p3; triIdx++; } }; struct TriangleAdder : public TriangleIndexFunctor { TriangleAdder(VertexList* vertices_, TriangleList* triangles_) { vertices = vertices_; triangles = triangles_; } }; struct is_not_soup { is_not_soup(const VertexList& vertices) : _vertices(vertices) {} bool operator()(const Triangle &t) { return _vertices[t.verts[0]].trisUsing > 1 || _vertices[t.verts[1]].trisUsing > 1 || _vertices[t.verts[2]].trisUsing > 1; } VertexList _vertices; }; class VertexCacheVisitor : osgUtil::VertexCacheVisitor { public: void optimizeVertices(Geometry& geom) { StatLogger logger("glesUtil::VertexCacheVisitor::optimizeVertices(" + geom.getName() + ")"); Array* vertArray = geom.getVertexArray(); if (!vertArray) return; unsigned vertArraySize = vertArray->getNumElements(); // If all the vertices fit in the cache, there's no point in // doing this optimization. if (vertArraySize <= 16) return; osg::ref_ptr dummy = new osg::Geometry; osg::Geometry::PrimitiveSetList newPrims; for (int ii = geom.getNumPrimitiveSets() - 1 ; ii >= 0 ; -- ii) { osg::PrimitiveSet* primitive = geom.getPrimitiveSet(ii); if(!primitive || !primitive->getNumIndices()) { continue; } // Collect all 'surface' primitives in the dummy geometry if(primitive->getMode() >= PrimitiveSet::TRIANGLES && primitive->getDrawElements()) { dummy->addPrimitiveSet(primitive); } else { newPrims.push_back(primitive); } } if(!dummy->getNumPrimitiveSets()) { return; } vector newVertList; doVertexOptimization(*dummy, newVertList); osg::DrawElementsUInt* elements = new DrawElementsUInt(GL_TRIANGLES, newVertList.begin(), newVertList.end()); if (geom.getUseVertexBufferObjects()) { elements->setElementBufferObject(new ElementBufferObject); } newPrims.insert(newPrims.begin(), elements); geom.setPrimitiveSetList(newPrims); geom.dirtyDisplayList(); } void doVertexOptimization(Geometry& geom, vector& vertDrawList) { Geometry::PrimitiveSetList& primSets = geom.getPrimitiveSetList(); // lists for all the vertices and triangles VertexList vertices; TriangleList triangles; TriangleCounter triCounter(&vertices); for (Geometry::PrimitiveSetList::iterator itr = primSets.begin(), end = primSets.end(); itr != end; ++itr) (*itr)->accept(triCounter); triangles.resize(triCounter.triangleCount); // Get total of triangles used by all the vertices size_t vertTrisSize = 0; for (VertexList::iterator itr = vertices.begin(), end = vertices.end(); itr != end; ++itr) { itr->triList = vertTrisSize; vertTrisSize += itr->trisUsing; } // Store for lists of triangles (indices) used by the vertices vector vertTriListStore(vertTrisSize); TriangleAdder triAdder(&vertices, &triangles); for (Geometry::PrimitiveSetList::iterator itr = primSets.begin(), end = primSets.end(); itr != end; ++itr) (*itr)->accept(triAdder); // discard triangle soup as it cannot be cache-optimized TriangleList::iterator soupIterator = std::partition(triangles.begin(), triangles.end(), is_not_soup(vertices)); TriangleList soup(soupIterator, triangles.end()); triangles.erase(soupIterator, triangles.end()); OSG_INFO << "Info: glesUtil::VertexCacheVisitor::doVertexOptimization(..) found " << soup.size() << " soup triangles" << std::endl << std::flush; std::vector indices; for(TriangleList::const_iterator it_tri = triangles.begin() ; it_tri != triangles.end() ; ++ it_tri) { indices.push_back(it_tri->verts[0]); indices.push_back(it_tri->verts[1]); indices.push_back(it_tri->verts[2]); } // call bgfx forsyth-algorithm implementation vertDrawList.resize(indices.size()); Forsyth::OptimizeFaces(&indices[0], indices.size(), vertices.size(), &vertDrawList[0], 16); for(TriangleList::iterator itr = soup.begin() ; itr != soup.end() ; ++ itr) { vertDrawList.push_back(itr->verts[0]); vertDrawList.push_back(itr->verts[1]); vertDrawList.push_back(itr->verts[2]); } } }; // Post-transform // A helper class that gathers up all the attribute arrays of an // osg::Geometry object that are BIND_PER_VERTEX and runs an // ArrayVisitor on them. struct GeometryArrayGatherer { typedef std::vector ArrayList; GeometryArrayGatherer(osg::Geometry& geometry) { add(geometry.getVertexArray()); add(geometry.getNormalArray()); add(geometry.getColorArray()); add(geometry.getSecondaryColorArray()); add(geometry.getFogCoordArray()); for(unsigned int i = 0 ; i < geometry.getNumTexCoordArrays() ; ++ i) { add(geometry.getTexCoordArray(i)); } for(unsigned int i = 0 ; i < geometry.getNumVertexAttribArrays() ; ++ i) { add(geometry.getVertexAttribArray(i)); } } void add(osg::Array* array) { if (array) { _arrayList.push_back(array); } } void accept(osg::ArrayVisitor& av) { for(ArrayList::iterator itr = _arrayList.begin() ; itr != _arrayList.end(); ++ itr) { (*itr)->accept(av); } } ArrayList _arrayList; }; // Compact the vertex attribute arrays. Also stolen from TriStripVisitor class RemapArray : public osg::ArrayVisitor { public: RemapArray(const IndexList& remapping) : _remapping(remapping) {} const IndexList& _remapping; template inline void remap(T& array) { for(unsigned int i = 0 ; i < _remapping.size() ; ++ i) { if(i != _remapping[i]) { array[i] = array[_remapping[i]]; } } array.erase(array.begin() + _remapping.size(), array.end()); } virtual void apply(osg::Array&) {} virtual void apply(osg::ByteArray& array) { remap(array); } virtual void apply(osg::ShortArray& array) { remap(array); } virtual void apply(osg::IntArray& array) { remap(array); } virtual void apply(osg::UByteArray& array) { remap(array); } virtual void apply(osg::UShortArray& array) { remap(array); } virtual void apply(osg::UIntArray& array) { remap(array); } virtual void apply(osg::FloatArray& array) { remap(array); } virtual void apply(osg::DoubleArray& array) { remap(array); } virtual void apply(osg::Vec2dArray& array) { remap(array); } virtual void apply(osg::Vec3dArray& array) { remap(array); } virtual void apply(osg::Vec4dArray& array) { remap(array); } virtual void apply(osg::Vec2Array& array) { remap(array); } virtual void apply(osg::Vec3Array& array) { remap(array); } virtual void apply(osg::Vec4Array& array) { remap(array); } virtual void apply(osg::Vec2iArray& array) { remap(array); } virtual void apply(osg::Vec3iArray& array) { remap(array); } virtual void apply(osg::Vec4iArray& array) { remap(array); } virtual void apply(osg::Vec2uiArray& array) { remap(array); } virtual void apply(osg::Vec3uiArray& array) { remap(array); } virtual void apply(osg::Vec4uiArray& array) { remap(array); } virtual void apply(osg::Vec2sArray& array) { remap(array); } virtual void apply(osg::Vec3sArray& array) { remap(array); } virtual void apply(osg::Vec4sArray& array) { remap(array); } virtual void apply(osg::Vec2usArray& array) { remap(array); } virtual void apply(osg::Vec3usArray& array) { remap(array); } virtual void apply(osg::Vec4usArray& array) { remap(array); } virtual void apply(osg::Vec2bArray& array) { remap(array); } virtual void apply(osg::Vec3bArray& array) { remap(array); } virtual void apply(osg::Vec4bArray& array) { remap(array); } virtual void apply(osg::Vec4ubArray& array) { remap(array); } virtual void apply(osg::Vec3ubArray& array) { remap(array); } virtual void apply(osg::Vec2ubArray& array) { remap(array); } virtual void apply(osg::MatrixfArray& array) { remap(array); } protected: RemapArray& operator= (const RemapArray&) { return *this; } }; // Compare vertices in a mesh using all their attributes. The vertices // are identified by their index. Extracted from TriStripVisitor.cpp struct VertexAttribComparitor : public GeometryArrayGatherer { VertexAttribComparitor(osg::Geometry& geometry) : GeometryArrayGatherer(geometry) {} bool operator() (unsigned int lhs, unsigned int rhs) const { for(ArrayList::const_iterator itr = _arrayList.begin(); itr != _arrayList.end(); ++ itr) { int compare = (*itr)->compare(lhs, rhs); if (compare == -1) { return true; } if (compare == 1) { return false; } } return false; } int compare(unsigned int lhs, unsigned int rhs) { for(ArrayList::iterator itr = _arrayList.begin(); itr != _arrayList.end(); ++ itr) { int compare = (*itr)->compare(lhs, rhs); if (compare == -1) { return -1; } if (compare == 1) { return 1; } } return 0; } protected: VertexAttribComparitor& operator= (const VertexAttribComparitor&) { return *this; } }; // Move the values in an array to new positions, based on the // remapping table. remapping[i] contains element i's new position, if // any. Unlike RemapArray in TriStripVisitor, this code doesn't // assume that elements only move downward in the array. class Remapper : public osg::ArrayVisitor { public: static const unsigned invalidIndex; Remapper(const vector& remapping) : _remapping(remapping), _newsize(0) { for (vector::const_iterator itr = _remapping.begin(), end = _remapping.end(); itr != end; ++itr) if (*itr != invalidIndex) ++_newsize; } const vector& _remapping; size_t _newsize; template inline void remap(T& array) { ref_ptr newarray = new T(_newsize); T* newptr = newarray.get(); for (size_t i = 0; i < array.size(); ++i) if (_remapping[i] != invalidIndex) (*newptr)[_remapping[i]] = array[i]; array.swap(*newptr); } virtual void apply(osg::Array&) {} virtual void apply(osg::ByteArray& array) { remap(array); } virtual void apply(osg::ShortArray& array) { remap(array); } virtual void apply(osg::IntArray& array) { remap(array); } virtual void apply(osg::UByteArray& array) { remap(array); } virtual void apply(osg::UShortArray& array) { remap(array); } virtual void apply(osg::UIntArray& array) { remap(array); } virtual void apply(osg::FloatArray& array) { remap(array); } virtual void apply(osg::DoubleArray& array) { remap(array); } virtual void apply(osg::Vec2Array& array) { remap(array); } virtual void apply(osg::Vec3Array& array) { remap(array); } virtual void apply(osg::Vec4Array& array) { remap(array); } virtual void apply(osg::Vec4ubArray& array) { remap(array); } virtual void apply(osg::Vec2bArray& array) { remap(array); } virtual void apply(osg::Vec3bArray& array) { remap(array); } virtual void apply(osg::Vec4bArray& array) { remap(array); } virtual void apply(osg::Vec2sArray& array) { remap(array); } virtual void apply(osg::Vec3sArray& array) { remap(array); } virtual void apply(osg::Vec4sArray& array) { remap(array); } virtual void apply(osg::Vec2dArray& array) { remap(array); } virtual void apply(osg::Vec3dArray& array) { remap(array); } virtual void apply(osg::Vec4dArray& array) { remap(array); } virtual void apply(osg::MatrixfArray& array) { remap(array); } }; // Record the order in which vertices in a Geometry are used. struct VertexReorderOperator { unsigned seq; std::vector remap; VertexReorderOperator() : seq(0) { } void inline doVertex(unsigned v) { if (remap[v] == glesUtil::Remapper::invalidIndex) { remap[v] = seq ++; } } void operator()(unsigned p1, unsigned p2, unsigned p3) { doVertex(p1); doVertex(p2); doVertex(p3); } void operator()(unsigned p1, unsigned p2) { doVertex(p1); doVertex(p2); } void operator()(unsigned p1) { doVertex(p1); } }; struct VertexReorder : public TriangleLinePointIndexFunctor { VertexReorder(unsigned numVerts) { remap.resize(numVerts, glesUtil::Remapper::invalidIndex); } }; template inline void reorderDrawElements(DE& drawElements, const vector& reorder) { for (typename DE::iterator itr = drawElements.begin(), end = drawElements.end(); itr != end; ++itr) { *itr = static_cast(reorder[*itr]); } } class VertexAccessOrderVisitor : osgUtil::VertexAccessOrderVisitor { struct OrderByPrimitiveMode { inline bool operator() (const osg::ref_ptr& prim1, const osg::ref_ptr& prim2) { if(prim1.get() && prim2.get()) { return prim1->getMode() >= prim2->getMode(); } else if(prim1.get()) { return true; } return false; } } order_by_primitive_mode; public: void optimizeOrder(Geometry& geom) { StatLogger logger("glesUtil::VertexAccessOrderVisitor::optimizeOrder(" + geom.getName() + ")"); Array* vertArray = geom.getVertexArray(); if (!vertArray || !vertArray->getNumElements()) return; Geometry::PrimitiveSetList& primSets = geom.getPrimitiveSetList(); // sort primitives: first triangles, then lines and finally points std::sort(primSets.begin(), primSets.end(), order_by_primitive_mode); glesUtil::VertexReorder vr(vertArray->getNumElements()); for (Geometry::PrimitiveSetList::iterator itr = primSets.begin(), end = primSets.end(); itr != end; ++itr) { PrimitiveSet* ps = itr->get(); PrimitiveSet::Type type = ps->getType(); if (type != PrimitiveSet::DrawElementsUBytePrimitiveType && type != PrimitiveSet::DrawElementsUShortPrimitiveType && type != PrimitiveSet::DrawElementsUIntPrimitiveType) return; ps->accept(vr); } // search for UVs array shared only within the geometry osgUtil::SharedArrayOptimizer deduplicator; deduplicator.findDuplicatedUVs(geom); // duplicate shared arrays as it isn't safe to rearrange vertices when arrays are shared. if (geom.containsSharedArrays()) geom.duplicateSharedArrays(); GeometryArrayGatherer gatherer(geom); Remapper remapper(vr.remap); gatherer.accept(remapper); for (Geometry::PrimitiveSetList::iterator itr = primSets.begin(), end = primSets.end(); itr != end; ++itr) { PrimitiveSet* ps = itr->get(); switch (ps->getType()) { case PrimitiveSet::DrawElementsUBytePrimitiveType: reorderDrawElements(*static_cast(ps), vr.remap); break; case PrimitiveSet::DrawElementsUShortPrimitiveType: reorderDrawElements(*static_cast(ps), vr.remap); break; case PrimitiveSet::DrawElementsUIntPrimitiveType: reorderDrawElements(*static_cast(ps), vr.remap); break; default: break; } } // deduplicate UVs array that were only shared within the geometry deduplicator.deduplicateUVs(geom); geom.dirtyDisplayList(); } }; } // glesUtil namespace #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/TriangleStripVisitor0000644000175000017500000000203313151044751027025 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef TRIANGLE_STRIP_VISITOR_H #define TRIANGLE_STRIP_VISITOR_H #include "GeometryUniqueVisitor" class TriangleStripVisitor : public GeometryUniqueVisitor { public: TriangleStripVisitor(unsigned int cacheSize, unsigned int minSize, bool merge): GeometryUniqueVisitor("TriangleStripVisitor"), _cacheSize(cacheSize), _minSize(minSize), _merge(merge) {} void apply(osg::Geometry& geometry); protected: void mergeTrianglesStrip(osg::Geometry& geometry); unsigned int _cacheSize; unsigned int _minSize; bool _merge; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/TriangleStripVisitor.cpp0000644000175000017500000001003313151044751027605 0ustar albertoalberto#include #include "TriangleStripVisitor" void TriangleStripVisitor::apply(osg::Geometry& geometry) { osgUtil::TriStripVisitor tristrip; tristrip.setCacheSize(_cacheSize); tristrip.setMinStripSize(_minSize); tristrip.stripify(geometry); // merge stritrip to one using degenerated triangles as glue if (_merge) { mergeTrianglesStrip(geometry); } } void TriangleStripVisitor::mergeTrianglesStrip(osg::Geometry& geometry) { int nbtristrip = 0; int nbtristripVertexes = 0; for (unsigned int i = 0; i < geometry.getNumPrimitiveSets(); i++) { osg::PrimitiveSet* ps = geometry.getPrimitiveSet(i); osg::DrawElements* de = ps->getDrawElements(); if (de && de->getMode() == osg::PrimitiveSet::TRIANGLE_STRIP) { nbtristrip++; nbtristripVertexes += de->getNumIndices(); } } if (nbtristrip > 0) { osg::notify(osg::NOTICE) << "found " << nbtristrip << " tristrip, " << "total vertexes " << nbtristripVertexes << " should result to " << nbtristripVertexes + nbtristrip*2 << " after connection" << std::endl; osg::DrawElementsUShort* ndw = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP); for (unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) { osg::PrimitiveSet* ps = geometry.getPrimitiveSet(i); if (ps && ps->getMode() == osg::PrimitiveSet::TRIANGLE_STRIP) { osg::DrawElements* de = ps->getDrawElements(); if (de) { // if connection needed insert degenerate triangles if (ndw->getNumIndices() != 0 && ndw->back() != de->getElement(0)) { // duplicate last vertex ndw->addElement(ndw->back()); // insert first vertex of next strip ndw->addElement(de->getElement(0)); } if (ndw->getNumIndices() % 2 != 0 ) { // add a dummy vertex to reverse the strip ndw->addElement(de->getElement(0)); } for (unsigned int j = 0; j < de->getNumIndices(); j++) { ndw->addElement(de->getElement(j)); } } else if (ps->getType() == osg::PrimitiveSet::DrawArraysPrimitiveType) { // trip strip can generate drawarray of 5 elements we want to merge them too osg::DrawArrays* da = dynamic_cast (ps); // if connection needed insert degenerate triangles if (ndw->getNumIndices() != 0 && ndw->back() != da->getFirst()) { // duplicate last vertex ndw->addElement(ndw->back()); // insert first vertex of next strip ndw->addElement(da->getFirst()); } if (ndw->getNumIndices() % 2 != 0 ) { // add a dummy vertex to reverse the strip ndw->addElement(da->getFirst()); } for (unsigned int j = 0; j < da->getNumIndices(); j++) { ndw->addElement(da->getFirst() + j); } } } } for (int i = geometry.getNumPrimitiveSets() - 1 ; i >= 0 ; -- i) { osg::PrimitiveSet* ps = geometry.getPrimitiveSet(i); // remove null primitive sets and all primitives that have been merged // (i.e. all TRIANGLE_STRIP DrawElements and DrawArrays) if (!ps || (ps && ps->getMode() == osg::PrimitiveSet::TRIANGLE_STRIP)) { geometry.getPrimitiveSetList().erase(geometry.getPrimitiveSetList().begin() + i); } } geometry.getPrimitiveSetList().insert(geometry.getPrimitiveSetList().begin(), ndw); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/IndexMeshVisitor0000644000175000017500000000200113151044751026115 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef INDEX_MESH_VISITOR #define INDEX_MESH_VISITOR #include "GeometryUniqueVisitor" class IndexMeshVisitor : public GeometryUniqueVisitor { public: IndexMeshVisitor(): GeometryUniqueVisitor("IndexMeshVisitor") {} void apply(osg::Geometry& geom); protected: typedef std::vector IndexList; void addDrawElements(IndexList&, osg::PrimitiveSet::Mode, osg::Geometry::PrimitiveSetList&, std::string userValue = std::string()); }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/IndexMeshVisitor.cpp0000644000175000017500000001344013151044751026707 0ustar albertoalberto#include #include // sort #include // numeric_limits #include #include #include #include #include "glesUtil" #include "IndexMeshVisitor" #include "PrimitiveIndexors" using namespace glesUtil; void IndexMeshVisitor::apply(osg::Geometry& geom) { // TODO: this is deprecated if (geom.getNormalBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; if (geom.getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; if (geom.getSecondaryColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; if (geom.getFogCoordBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; // no point optimizing if we don't have enough vertices. if (!geom.getVertexArray() || geom.getVertexArray()->getNumElements() < 3) return; osgUtil::SharedArrayOptimizer deduplicator; deduplicator.findDuplicatedUVs(geom); // duplicate shared arrays as it isn't safe to rearrange vertices when arrays are shared. if (geom.containsSharedArrays()) { geom.duplicateSharedArrays(); } osg::Geometry::PrimitiveSetList& primitives = geom.getPrimitiveSetList(); osg::Geometry::PrimitiveSetList::iterator itr; osg::Geometry::PrimitiveSetList new_primitives; new_primitives.reserve(primitives.size()); // compute duplicate vertices typedef std::vector IndexList; unsigned int numVertices = geom.getVertexArray()->getNumElements(); IndexList indices(numVertices); unsigned int i, j; for(i = 0 ; i < numVertices ; ++ i) { indices[i] = i; } VertexAttribComparitor arrayComparitor(geom); std::sort(indices.begin(), indices.end(), arrayComparitor); unsigned int lastUnique = 0; unsigned int numUnique = 1; for(i = 1 ; i < numVertices ; ++ i) { if (arrayComparitor.compare(indices[lastUnique], indices[i]) != 0) { lastUnique = i; ++ numUnique; } } IndexList remapDuplicatesToOrignals(numVertices); lastUnique = 0; for(i = 1 ; i < numVertices ; ++ i) { if (arrayComparitor.compare(indices[lastUnique],indices[i]) != 0) { // found a new vertex entry, so previous run of duplicates needs // to be put together. unsigned int min_index = indices[lastUnique]; for(j = lastUnique + 1 ; j < i ; ++ j) { min_index = osg::minimum(min_index, indices[j]); } for(j = lastUnique ; j < i ; ++ j) { remapDuplicatesToOrignals[indices[j]] = min_index; } lastUnique = i; } } unsigned int min_index = indices[lastUnique]; for(j = lastUnique + 1 ; j < i ; ++ j) { min_index = osg::minimum(min_index, indices[j]); } for(j = lastUnique ; j < i ; ++ j) { remapDuplicatesToOrignals[indices[j]] = min_index; } // copy the arrays. IndexList finalMapping(numVertices); IndexList copyMapping; copyMapping.reserve(numUnique); unsigned int currentIndex = 0; for(i = 0 ; i < numVertices ; ++ i) { if (remapDuplicatesToOrignals[i] == i) { finalMapping[i] = currentIndex; copyMapping.push_back(i); currentIndex++; } else { finalMapping[i] = finalMapping[remapDuplicatesToOrignals[i]]; } } // remap any shared vertex attributes RemapArray ra(copyMapping); arrayComparitor.accept(ra); // triangulate faces { TriangleIndexor ti; ti._maxIndex = numVertices; ti._remapping = finalMapping; for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) { (*itr)->accept(ti); } addDrawElements(ti._indices, osg::PrimitiveSet::TRIANGLES, new_primitives); } // line-ify line-type primitives { LineIndexor li, wi; // lines and wireframes li._maxIndex = numVertices; wi._maxIndex = numVertices; li._remapping = finalMapping; wi._remapping = finalMapping; for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) { bool isWireframe = false; if((*itr)->getUserValue("wireframe", isWireframe) && isWireframe) { (*itr)->accept(wi); } else { (*itr)->accept(li); } } addDrawElements(li._indices, osg::PrimitiveSet::LINES, new_primitives); addDrawElements(wi._indices, osg::PrimitiveSet::LINES, new_primitives, "wireframe"); } // adds points primitives { IndexList points; for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) { if((*itr) && (*itr)->getMode() == osg::PrimitiveSet::POINTS) { for(unsigned int k = 0 ; k < (*itr)->getNumIndices() ; ++ k) { points.push_back(finalMapping[(*itr)->index(k)]); } } } addDrawElements(points, osg::PrimitiveSet::POINTS, new_primitives); } geom.setPrimitiveSetList(new_primitives); deduplicator.deduplicateUVs(geom); setProcessed(&geom); } void IndexMeshVisitor::addDrawElements(IndexList& data, osg::PrimitiveSet::Mode mode, osg::Geometry::PrimitiveSetList& primitives, std::string userValue) { if(!data.empty()) { osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(mode, data.begin(), data.end()); if(!userValue.empty()) { elements->setUserValue(userValue, true); } primitives.push_back(elements); } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/CMakeLists.txt0000644000175000017500000000042613151044751025477 0ustar albertoalbertoSET(TARGET_SRC ReaderWriterGLES.cpp OpenGLESGeometryOptimizer.cpp TriangleStripVisitor.cpp IndexMeshVisitor.cpp UnIndexMeshVisitor.cpp forsythtriangleorderoptimizer.cpp) #### end var setup ### SET(TARGET_ADDED_LIBRARIES osgUtil) SETUP_PLUGIN(gles) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/PreTransformVisitor0000644000175000017500000000164013151044751026663 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef PRE_TRANSFORM_VISITOR #define PRE_TRANSFORM_VISITOR #include "GeometryUniqueVisitor" #include "glesUtil" class PreTransformVisitor : public GeometryUniqueVisitor { public: PreTransformVisitor(): GeometryUniqueVisitor("PreTransformVisitor") {} void apply(osg::Geometry& geometry) { glesUtil::VertexAccessOrderVisitor optimizer; optimizer.optimizeOrder(geometry); setProcessed(&geometry); } }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/DetachPrimitiveVisitor0000644000175000017500000000701313151044751027322 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef DETACH_PRIMITIVE_VISITOR #define DETACH_PRIMITIVE_VISITOR #include #include "GeometryUniqueVisitor" class DetachPrimitiveVisitor : public GeometryUniqueVisitor { public: DetachPrimitiveVisitor(std::string const& userValue, bool keepGeometryAttributes=false, bool inlined=true): GeometryUniqueVisitor("DetachPrimitiveVisitor"), _userValue(userValue), _keepGeometryAttributes(keepGeometryAttributes), _inlined(inlined) {} void apply(osg::Geometry& geometry) { if(shouldDetach(geometry)) { osg::Geometry* detached = createDetachedGeometry(geometry); unsigned int nbParents = geometry.getNumParents(); for(unsigned int i = 0 ; i < nbParents ; ++ i) { osg::Node* parent = geometry.getParent(i); // TODO: Geode will be soon deprecated if(parent && parent->asGeode()) { osg::Geode* geode = parent->asGeode(); geode->addDrawable(detached); if(!_inlined) { geode->removeDrawable(&geometry); } } } setProcessed(detached); } setProcessed(&geometry); } protected: bool shouldDetach(osg::Geometry& geometry) { bool detach = false; for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) { osg::PrimitiveSet* primitive = geometry.getPrimitiveSet(i); if(primitive && primitive->getUserValue(_userValue, detach) && detach) { return true; } } return false; } osg::Geometry* createDetachedGeometry(osg::Geometry& source) { osg::Geometry* detached = new osg::Geometry(source, osg::CopyOp::SHALLOW_COPY); if(!_keepGeometryAttributes) { // we keep only vertexes and clean all other attributes and values detached->setNormalArray(0); detached->setColorArray(0); detached->setSecondaryColorArray(0); detached->setFogCoordArray(0); for (unsigned int i = 0 ; i < source.getNumTexCoordArrays(); ++ i) { detached->setTexCoordArray(i, 0); } detached->getVertexAttribArrayList().clear(); detached->setStateSet(0); detached->setUserDataContainer(0); } // filter primitivesets osg::Geometry::PrimitiveSetList detachedPrimitives; for(int i = source.getNumPrimitiveSets() - 1 ; i >= 0 ; -- i) { osg::PrimitiveSet* primitive = source.getPrimitiveSet(i); bool isTrue = false; if(primitive && primitive->getUserValue(_userValue, isTrue) && isTrue) { detachedPrimitives.push_back(primitive); source.removePrimitiveSet(i); } } detached->setPrimitiveSetList(detachedPrimitives); detached->setUserValue(_userValue, true); return detached; } std::string _userValue; bool _keepGeometryAttributes; bool _inlined; }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/OpenGLESGeometryOptimizer.cpp0000644000175000017500000000237013151044751030436 0ustar albertoalberto#include #include "OpenGLESGeometryOptimizer" #include "glesUtil" const unsigned glesUtil::Remapper::invalidIndex = std::numeric_limits::max(); osg::Node* OpenGLESGeometryOptimizer::optimize(osg::Node& node) { osg::ref_ptr model = osg::clone(&node); // animation: create regular Geometry if RigGeometry makeAnimation(model.get()); // wireframe if (!_wireframe.empty()) { makeWireframe(model.get()); } // bind per vertex makeBindPerVertex(model.get()); // index (merge exact duplicates + uses simple triangles & lines i.e. no strip/fan/loop) makeIndexMesh(model.get()); // tangent space if (_generateTangentSpace) { makeTangentSpace(model.get()); } if(!_useDrawArray) { // split geometries having some primitive index > _maxIndexValue makeSplit(model.get()); } // strip if(!_disableTriStrip) { makeTriStrip(model.get()); } if(_useDrawArray) { // drawelements to drawarrays makeDrawArray(model.get()); } else if(!_disablePreTransform) { // pre-transform makePreTransform(model.get()); } // detach wireframe makeDetach(model.get()); return model.release(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/UnIndexMeshVisitor.cpp0000644000175000017500000001044713151044751027216 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #include #include #include "UnIndexMeshVisitor" #include "GeometryArray" #include "PrimitiveIndexors" typedef std::vector IndexList; // this help works only for indexed primitive to unindex it void UnIndexMeshVisitor::apply(osg::Geometry& geom) { // no point optimizing if we don't have enough vertices. if (!geom.getVertexArray()) return; // check for the existence of surface primitives unsigned int numIndexedPrimitives = 0; osg::Geometry::PrimitiveSetList& primitives = geom.getPrimitiveSetList(); osg::Geometry::PrimitiveSetList::iterator itr; for(itr=primitives.begin(); itr!=primitives.end(); ++itr) { osg::PrimitiveSet::Type type = (*itr)->getType(); if ((type == osg::PrimitiveSet::DrawElementsUBytePrimitiveType || type == osg::PrimitiveSet::DrawElementsUShortPrimitiveType || type == osg::PrimitiveSet::DrawElementsUIntPrimitiveType)) numIndexedPrimitives++; } // no polygons or no indexed primitive, nothing to do if (!numIndexedPrimitives) { return; } // we dont manage lines GeometryArrayList arraySrc(geom); GeometryArrayList arrayList = arraySrc.cloneType(); osg::Geometry::PrimitiveSetList newPrimitives; for(itr=primitives.begin(); itr!=primitives.end(); ++itr) { osg::PrimitiveSet::Mode mode = (osg::PrimitiveSet::Mode)(*itr)->getMode(); switch(mode) { // manage triangles case(osg::PrimitiveSet::TRIANGLES): case(osg::PrimitiveSet::TRIANGLE_STRIP): case(osg::PrimitiveSet::TRIANGLE_FAN): case(osg::PrimitiveSet::QUADS): case(osg::PrimitiveSet::QUAD_STRIP): case(osg::PrimitiveSet::POLYGON): { // for each geometry list indexes of vertexes // to makes triangles TriangleIndexor triangleIndexList; (*itr)->accept(triangleIndexList); unsigned int index = arrayList.size(); // now copy each vertex to new array, like a draw array arraySrc.append(triangleIndexList._indices, arrayList); newPrimitives.push_back(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, index, triangleIndexList._indices.size())); } break; // manage lines case(osg::PrimitiveSet::LINES): case(osg::PrimitiveSet::LINE_STRIP): case(osg::PrimitiveSet::LINE_LOOP): { EdgeIndexor edgesIndexList; (*itr)->accept(edgesIndexList); unsigned int index = arrayList.size(); // now copy each vertex to new array, like a draw array arraySrc.append(edgesIndexList._indices, arrayList); newPrimitives.push_back(new osg::DrawArrays(osg::PrimitiveSet::LINES, index, edgesIndexList._indices.size())); } break; case(osg::PrimitiveSet::POINTS): { PointIndexor pointsIndexList; (*itr)->accept(pointsIndexList); unsigned int index = arrayList.size(); // now copy each vertex to new array, like a draw array arraySrc.append(pointsIndexList._indices, arrayList); newPrimitives.push_back(new osg::DrawArrays(osg::PrimitiveSet::POINTS, index, pointsIndexList._indices.size())); } break; default: break; } } arrayList.setToGeometry(geom); geom.setPrimitiveSetList(newPrimitives); setProcessed(&geom); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgPlugins/gles/BindPerVertexVisitor0000644000175000017500000002206313151044751026764 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commercial and non commercial * applications, as long as this copyright notice is maintained. * * This application 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. * */ #ifndef BIND_PER_VERTEX_VISITOR #define BIND_PER_VERTEX_VISITOR #include "GeometryUniqueVisitor" // TODO: deprecated class BindPerVertexVisitor : public GeometryUniqueVisitor { public: BindPerVertexVisitor(): GeometryUniqueVisitor("BindPerVertexVisitor") {} void apply(osg::Geometry& geometry) { if (geometry.getNormalArray() && geometry.getNormalBinding() != osg::Geometry::BIND_PER_VERTEX) { bindPerVertex(geometry.getNormalArray(), geometry.getNormalBinding(), geometry.getPrimitiveSetList()); geometry.setNormalBinding(osg::Geometry::BIND_PER_VERTEX); } if (geometry.getColorArray() && geometry.getColorBinding() != osg::Geometry::BIND_PER_VERTEX) { bindPerVertex(geometry.getColorArray(), geometry.getColorBinding(), geometry.getPrimitiveSetList()); geometry.setColorBinding(osg::Geometry::BIND_PER_VERTEX); } if (geometry.getSecondaryColorArray() && geometry.getSecondaryColorBinding() != osg::Geometry::BIND_PER_VERTEX) { bindPerVertex(geometry.getSecondaryColorArray(), geometry.getSecondaryColorBinding(), geometry.getPrimitiveSetList()); geometry.setSecondaryColorBinding(osg::Geometry::BIND_PER_VERTEX); } if (geometry.getFogCoordArray() && geometry.getFogCoordBinding() != osg::Geometry::BIND_PER_VERTEX) { bindPerVertex(geometry.getFogCoordArray(), geometry.getFogCoordBinding(), geometry.getPrimitiveSetList()); geometry.setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX); } setProcessed(&geometry); }; protected: void bindPerVertex(osg::Array* src, osg::Geometry::AttributeBinding fromBinding, osg::Geometry::PrimitiveSetList& primitives) { if (doConvert(src, fromBinding, primitives)) return; if (doConvert(src, fromBinding, primitives)) return; if (doConvert(src, fromBinding, primitives)) return; if (doConvert(src, fromBinding, primitives)) return; } template bool doConvert(osg::Array* src, osg::Geometry::AttributeBinding fromBinding, osg::Geometry::PrimitiveSetList& primitives) { T* array= dynamic_cast(src); if (array) { convert(*array, fromBinding, primitives); return true; } return false; } template void convert(T& array, osg::Geometry::AttributeBinding fromBinding, osg::Geometry::PrimitiveSetList& primitives) { osg::ref_ptr result = new T(); for (unsigned int p = 0; p < primitives.size(); p++) { switch ( primitives[p]->getMode() ) { case osg::PrimitiveSet::POINTS: osg::notify(osg::WARN) << "ConvertToBindPerVertex not supported for POINTS" << std::endl; break; case osg::PrimitiveSet::LINE_STRIP: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { unsigned int nb = primitives[p]->getNumIndices(); for (unsigned int i = 0; i < nb; i++) result->push_back(array[p]); } break; } break; case osg::PrimitiveSet::LINES: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { unsigned int nb = primitives[p]->getNumIndices(); for (unsigned int i = 0; i < nb; i++) result->push_back(array[p]); } break; } break; case osg::PrimitiveSet::TRIANGLES: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { unsigned int nb = primitives[p]->getNumIndices(); for (unsigned int i = 0; i < nb; i++) result->push_back(array[p]); } break; } break; case osg::PrimitiveSet::TRIANGLE_STRIP: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { osg::notify(osg::FATAL) << "Can't convert Array from BIND_PER_PRIMITIVE_SET to BIND_PER_VERTEX, for TRIANGLE_STRIP" << std::endl; } break; } break; case osg::PrimitiveSet::TRIANGLE_FAN: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { osg::notify(osg::FATAL) << "Can't convert Array from BIND_PER_PRIMITIVE_SET to BIND_PER_VERTEX, for TRIANGLE_FAN" << std::endl; } break; } break; case osg::PrimitiveSet::QUADS: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { osg::notify(osg::FATAL) << "Can't convert Array from BIND_PER_PRIMITIVE_SET to BIND_PER_VERTEX, for QUADS" << std::endl; } break; } break; case osg::PrimitiveSet::QUAD_STRIP: switch(fromBinding) { case osg::Geometry::BIND_OFF: case osg::Geometry::BIND_PER_VERTEX: break; case osg::Geometry::BIND_OVERALL: { for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++) result->push_back(array[0]); } break; case osg::Geometry::BIND_PER_PRIMITIVE_SET: { osg::notify(osg::FATAL) << "Can't convert Array from BIND_PER_PRIMITIVE_SET to BIND_PER_VERTEX, for QUAD_STRIP" << std::endl; } break; } break; } } array = *result; } }; #endif OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/0000755000175000017500000000000013151044751020677 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Version.cpp0000644000175000017500000000152713151044751023035 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include extern "C" { const char* osgFXGetVersion() { return osgGetVersion(); } const char* osgFXGetLibraryName() { return "OpenSceneGraph FX (Special effects) Library"; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Scribe.cpp0000644000175000017500000000605513151044751022620 0ustar albertoalberto#include #include #include #include #include #include #include #include using namespace osgFX; namespace { // register a prototype for this effect Registry::Proxy proxy(new Scribe); // default technique class class DefaultTechnique: public Technique { public: DefaultTechnique(osg::Material* wf_mat, osg::LineWidth* wf_lw) : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw) {} bool validate(osg::State& ) const { return strncmp((const char*)glGetString(GL_VERSION), "1.1", 3) >= 0; } protected: void define_passes() { // implement pass #1 { osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr polyoffset = new osg::PolygonOffset; polyoffset->setFactor(1.0f); polyoffset->setUnits(1.0f); ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); addPass(ss.get()); } // implement pass #2 { osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr polymode = new osg::PolygonMode; polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); addPass(ss.get()); } } private: osg::ref_ptr _wf_mat; osg::ref_ptr _wf_lw; }; } Scribe::Scribe() : Effect(), _wf_mat(new osg::Material), _wf_lw(new osg::LineWidth) { _wf_lw->setWidth(1.0f); _wf_mat->setColorMode(osg::Material::OFF); _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); _wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(1.0f,1.0f,1.0f,1.0f)); } Scribe::Scribe(const Scribe& copy, const osg::CopyOp& copyop) : Effect(copy, copyop), _wf_mat(static_cast(copyop(copy._wf_mat.get()))), _wf_lw(static_cast(copyop(copy._wf_lw.get()))) { } bool Scribe::define_techniques() { addTechnique(new DefaultTechnique(_wf_mat.get(), _wf_lw.get())); return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Cartoon.cpp0000644000175000017500000003102413151044751023010 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgFX; namespace { osg::Image* create_sharp_lighting_map(int levels = 4, int texture_size = 16) { osg::ref_ptr image = new osg::Image; image->setImage(texture_size, 1, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, new unsigned char[4*texture_size], osg::Image::USE_NEW_DELETE); for (int i=0; i(texture_size); c = (1+static_cast(sqrtf(c) * (levels))) / static_cast(levels+1); *(image->data(i, 0)+0) = static_cast(c*255); *(image->data(i, 0)+1) = static_cast(c*255); *(image->data(i, 0)+2) = static_cast(c*255); *(image->data(i, 0)+3) = 255; } return image.release(); } } namespace { // register a prototype for this effect Registry::Proxy proxy(new Cartoon); // default technique class class DefaultTechnique: public Technique { public: DefaultTechnique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum) : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {} void getRequiredExtensions(std::vector& extensions) const { extensions.push_back("GL_ARB_vertex_program"); } protected: void define_passes() { // implement pass #1 (solid surfaces) { std::ostringstream vp_oss; vp_oss << "!!ARBvp1.0\n" "OPTION ARB_position_invariant;" "PARAM c0 = { 0, 0, 0, 0 };" "TEMP R0, R1;" "ATTRIB v18 = vertex.normal;" "PARAM s18 = state.light[" << _lightnum << "].position;" "PARAM s16 = state.light[" << _lightnum << "].diffuse;" "PARAM s1 = state.material.diffuse;" "PARAM s631[4] = { state.matrix.modelview.invtrans };" "MOV R0, s1;" "MUL result.color.front.primary, R0, s16;" "DP4 R0.x, s18, s18;" "RSQ R0.x, R0.x;" "MUL R1, R0.x, s18;" "DP4 R0.x, s631[0], v18;" "DP4 R0.y, s631[1], v18;" "DP4 R0.z, s631[2], v18;" "DP4 R0.w, s631[3], v18;" "DP4 R0.x, R1, R0;" "MAX result.texcoord[0].x, c0.x, R0.x;" "END"; osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr polyoffset = new osg::PolygonOffset; polyoffset->setFactor(1.0f); polyoffset->setUnits(1.0f); ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr vp = new osg::VertexProgram; vp->setVertexProgram(vp_oss.str()); ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF); osg::ref_ptr texture = new osg::Texture1D; texture->setImage(create_sharp_lighting_map()); texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); osg::ref_ptr texenv = new osg::TexEnv; texenv->setMode(osg::TexEnv::MODULATE); ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); addPass(ss.get()); } // implement pass #2 (outlines) { osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr polymode = new osg::PolygonMode; polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr cf = new osg::CullFace; cf->setMode(osg::CullFace::FRONT); ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); _wf_mat->setColorMode(osg::Material::OFF); _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); // set by outline colour so no need to set here. //_wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); addPass(ss.get()); } } private: osg::ref_ptr _wf_mat; osg::ref_ptr _wf_lw; int _lightnum; }; } /////////////////////////////////////////////////////////////////////////// // A port of Marco Jez's "cartoon.cg" to the OpenGL Shading Language // by Mike Weiblen 2003-10-03, // // This shader is simplified due to limitations in the OGLSL implementation // in the current 3Dlabs driver. As the OGLSL implementation improves, // need to revisit and enhance this shader. namespace { class OGLSL_Technique : public Technique { public: OGLSL_Technique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum) : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {} void getRequiredExtensions(std::vector& extensions) const { extensions.push_back( "GL_ARB_shader_objects" ); extensions.push_back( "GL_ARB_vertex_shader" ); extensions.push_back( "GL_ARB_fragment_shader" ); } protected: void define_passes() { // implement pass #1 (solid surfaces) { std::ostringstream vert_source; vert_source << "varying float CartoonTexCoord;\n" "void main( void )\n" "{\n" " vec4 LightPosition = gl_LightSource["<<_lightnum<<"].position;\n" " vec3 LightDirection;\n" " if (LightPosition[3]!=0.0) { \n" " vec4 eye_space_position = gl_ModelViewMatrix * gl_Vertex;\n" " LightDirection = (LightPosition.xyz-eye_space_position.xyz);\n" " } else {\n" " LightDirection = LightPosition.xyz;\n" " }\n" " vec3 eye_space_normal = normalize(gl_NormalMatrix * gl_Normal);\n" " CartoonTexCoord = max(0.0, dot(normalize(LightDirection), eye_space_normal));\n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" "}\n"; const char * frag_source = "uniform sampler1D CartoonTexUnit;" "varying float CartoonTexCoord;" "void main( void )" "{" "gl_FragColor = texture1D( CartoonTexUnit, CartoonTexCoord );" "}"; osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr polyoffset = new osg::PolygonOffset; polyoffset->setFactor(1.0f); polyoffset->setUnits(1.0f); ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr program = new osg::Program; program->addShader( new osg::Shader( osg::Shader::VERTEX, vert_source.str() ) ); program->addShader( new osg::Shader( osg::Shader::FRAGMENT, frag_source ) ); ss->addUniform( new osg::Uniform("CartoonTexUnit", 0)); ss->setAttributeAndModes( program.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF); osg::ref_ptr texture = new osg::Texture1D; texture->setImage(create_sharp_lighting_map()); texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); osg::ref_ptr texenv = new osg::TexEnv; texenv->setMode(osg::TexEnv::MODULATE); ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); addPass(ss.get()); } // implement pass #2 (outlines) { osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr polymode = new osg::PolygonMode; polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr cf = new osg::CullFace; cf->setMode(osg::CullFace::FRONT); ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); _wf_mat->setColorMode(osg::Material::OFF); _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); // set by outline colour so no need to set here. //_wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); addPass(ss.get()); } } private: osg::ref_ptr _wf_mat; osg::ref_ptr _wf_lw; int _lightnum; }; } /////////////////////////////////////////////////////////////////////////// Cartoon::Cartoon() : Effect(), _wf_mat(new osg::Material), _wf_lw(new osg::LineWidth(2.0f)), _lightnum(0) { setOutlineColor(osg::Vec4(0, 0, 0, 1)); } Cartoon::Cartoon(const Cartoon& copy, const osg::CopyOp& copyop) : Effect(copy, copyop), _wf_mat(static_cast(copyop(copy._wf_mat.get()))), _wf_lw(static_cast(copyop(copy._wf_lw.get()))), _lightnum(copy._lightnum) { } bool Cartoon::define_techniques() { addTechnique(new DefaultTechnique(_wf_mat.get(), _wf_lw.get(), _lightnum)); addTechnique(new OGLSL_Technique(_wf_mat.get(), _wf_lw.get(), _lightnum)); return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/BumpMapping.cpp0000644000175000017500000006260613151044751023634 0ustar albertoalberto#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgFX; namespace { using osg::NodeVisitor; // this is a visitor class that prepares all geometries in a subgraph // by calling prepareGeometry() which in turn generates tangent-space // basis vectors class TsgVisitor: public NodeVisitor { public: TsgVisitor(BumpMapping* bm): NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), _bm(bm) {} META_NodeVisitor("osgFX","TsgVisitor") void apply(osg::Geode& geode) { for (unsigned i=0; i(geode.getDrawable(i)); if (geo) { _bm->prepareGeometry(geo); } } NodeVisitor::apply(geode); } private: BumpMapping* _bm; }; // this visitor generates texture coordinates for all geometries in a // subgraph. It is used only for demo purposes. class TexCoordGenerator: public osg::NodeVisitor { public: TexCoordGenerator(int du, int nu): NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), du_(du), nu_(nu) {} META_NodeVisitor("osgFX","TexCoordGenerator") void apply(osg::Geode& geode) { const osg::BoundingSphere &bsphere = geode.getBound(); float scale = 10; if (bsphere.radius() != 0) { scale = 5 / bsphere.radius(); } for (unsigned i=0; i(geode.getDrawable(i)); if (geo) { osg::ref_ptr tc = generate_coords(geo->getVertexArray(), geo->getNormalArray(), scale); geo->setTexCoordArray(du_, tc.get()); geo->setTexCoordArray(nu_, tc.get()); } } NodeVisitor::apply(geode); } protected: osg::Vec2Array* generate_coords(osg::Array* vx, osg::Array* nx, float scale) { osg::Vec2Array* v2a = dynamic_cast(vx); osg::Vec3Array* v3a = dynamic_cast(vx); osg::Vec4Array* v4a = dynamic_cast(vx); osg::Vec2Array* n2a = dynamic_cast(nx); osg::Vec3Array* n3a = dynamic_cast(nx); osg::Vec4Array* n4a = dynamic_cast(nx); osg::ref_ptr tc = new osg::Vec2Array; for (unsigned i=0; igetNumElements(); ++i) { osg::Vec3 P; if (v2a) P.set((*v2a)[i].x(), (*v2a)[i].y(), 0); if (v3a) P.set((*v3a)[i].x(), (*v3a)[i].y(), (*v3a)[i].z()); if (v4a) P.set((*v4a)[i].x(), (*v4a)[i].y(), (*v4a)[i].z()); osg::Vec3 N(0, 0, 1); if (n2a) N.set((*n2a)[i].x(), (*n2a)[i].y(), 0); if (n3a) N.set((*n3a)[i].x(), (*n3a)[i].y(), (*n3a)[i].z()); if (n4a) N.set((*n4a)[i].x(), (*n4a)[i].y(), (*n4a)[i].z()); int axis = 0; if (N.y() > N.x() && N.y() > N.z()) axis = 1; if (-N.y() > N.x() && -N.y() > N.z()) axis = 1; if (N.z() > N.x() && N.z() > N.y()) axis = 2; if (-N.z() > N.x() && -N.z() > N.y()) axis = 2; osg::Vec2 uv; switch (axis) { case 0: uv.set(P.y(), P.z()); break; case 1: uv.set(P.x(), P.z()); break; case 2: uv.set(P.x(), P.y()); break; default: ; } tc->push_back(uv * scale); } return tc.release(); } private: int du_; int nu_; }; } namespace { const unsigned int NO_VALID_CONTEXT = 0xffffffff; // a state attribute class that grabs the initial inverse view matrix // and sends it to a VertexProgram. // NOTE: due to lack of support for per-context parameters in VertexProgram, // this class will send the matrix to the vp only while the first context // is being rendered. All subsequent contexts will use the first context's // matrix. class ViewMatrixExtractor: public osg::StateAttribute { public: ViewMatrixExtractor() : osg::StateAttribute(), _vp(0), _param(0), _first_context(NO_VALID_CONTEXT) { } ViewMatrixExtractor(const ViewMatrixExtractor& copy, const osg::CopyOp& copyop) : osg::StateAttribute(copy, copyop), _vp(static_cast(copyop(copy._vp.get()))), _param(copy._param), _first_context(NO_VALID_CONTEXT) { } ViewMatrixExtractor(osg::VertexProgram* vp, int param) : osg::StateAttribute(), _vp(vp), _param(param), _first_context(NO_VALID_CONTEXT) { } META_StateAttribute(osgFX, ViewMatrixExtractor, VIEWMATRIXEXTRACTOR); int compare(const osg::StateAttribute& sa) const { COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa); if (_vp.get() != rhs._vp.get()) return -1; if (_param < rhs._param) return -1; if (_param > rhs._param) return 1; return 0; } void apply(osg::State& state) const { if (_first_context == NO_VALID_CONTEXT) { _first_context = state.getContextID(); } if (state.getContextID() == _first_context) { if (_vp.valid()) { osg::Matrix M = state.getInitialInverseViewMatrix(); for (int i=0; i<4; ++i) { _vp->setProgramLocalParameter(_param+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i))); } } } } private: mutable osg::ref_ptr _vp; int _param; mutable unsigned int _first_context; }; } namespace { // let's register this cool effect! :) Registry::Proxy proxy(new BumpMapping); } namespace { // "Full ARB" technique uses ARB vertex program and fragment program. // Handles ambient, diffuse and specular lighting transparently. A texture // for the diffuse component is required as well as a normal map texture. class FullArbTechnique: public Technique { public: FullArbTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D* diffuse_tex, osg::Texture2D* normal_tex) : Technique(), _lightnum(lightnum), _diffuse_unit(diffuseunit), _normal_unit(normalunit), _diffuse_tex(diffuse_tex), _normal_tex(normal_tex) { } META_Technique( "FullArbTechnique", "Single-pass technique, requires ARB_vertex_program and ARB_fragment_program." ); void getRequiredExtensions(std::vector& extensions) const { extensions.push_back("GL_ARB_vertex_program"); extensions.push_back("GL_ARB_fragment_program"); } protected: void define_passes() { int freeunit; for (freeunit=0; freeunit==_diffuse_unit||freeunit==_normal_unit; ++freeunit) {} // vertex program std::ostringstream vp_oss; vp_oss << "!!ARBvp1.0\n" "OPTION ARB_position_invariant;" "PARAM c4 = { 0, 0, 0, 1 };" "PARAM c5 = { 0.5, 4, 0, 0 };" "TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8;" "ATTRIB v5 = vertex.attrib[15];" "ATTRIB v4 = vertex.attrib[7];" "ATTRIB v3 = vertex.attrib[6];" "ATTRIB v25 = vertex.texcoord[" << _diffuse_unit << "];" "ATTRIB v24 = vertex.texcoord[" << _normal_unit << "];" "ATTRIB v18 = vertex.normal;" "ATTRIB v16 = vertex.position;" "PARAM s259[4] = { state.matrix.mvp };" "PARAM s18 = state.light["<<_lightnum<<"].position;" "PARAM s77 = state.lightprod["<<_lightnum<<"].specular;" "PARAM s4 = state.material.shininess;" "PARAM s75 = state.lightprod["<<_lightnum<<"].ambient;" "PARAM s223[4] = { state.matrix.modelview };" "PARAM c0[4] = { program.local[0..3] };" " MOV result.texcoord[" << freeunit << "].xyz, s75.xyzx;" " MOV result.texcoord[" << freeunit << "].w, s4.x;" " MOV result.texcoord[" << _normal_unit << "].zw, s77.zwzw;" " MOV result.texcoord[" << _normal_unit << "].xy, v24;" " MOV result.texcoord[" << _diffuse_unit << "].zw, s77.xyxy;" " MOV result.texcoord[" << _diffuse_unit << "].xy, v25;" " MOV R5, c0[0];" " MUL R0, R5.y, s223[1];" " MAD R0, R5.x, s223[0], R0;" " MAD R0, R5.z, s223[2], R0;" " MAD R0, R5.w, s223[3], R0;" " DP4 R1.x, R0, v16;" " MOV R4, c0[1];" " MUL R2, R4.y, s223[1];" " MAD R2, R4.x, s223[0], R2;" " MAD R2, R4.z, s223[2], R2;" " MAD R7, R4.w, s223[3], R2;" " DP4 R1.y, R7, v16;" " MOV R3, c0[2];" " MUL R2, R3.y, s223[1];" " MAD R2, R3.x, s223[0], R2;" " MAD R2, R3.z, s223[2], R2;" " MAD R6, R3.w, s223[3], R2;" " DP4 R1.z, R6, v16;" " MOV R2, c0[3];" " MUL R8, R2.y, s223[1];" " MAD R8, R2.x, s223[0], R8;" " MAD R8, R2.z, s223[2], R8;" " MAD R8, R2.w, s223[3], R8;" " MOV R8.x, R5.w;" " MOV R8.y, R4.w;" " MOV R8.z, R3.w;" " ADD R1.yzw, R8.xxyz, -R1.xxyz;" " DP3 R1.x, R1.yzwy, R1.yzwy;" " RSQ R1.x, R1.x;" " DP4 R5.x, R5, s18;" " DP4 R5.y, R4, s18;" " DP4 R5.z, R3, s18;" " DP3 R2.x, R5.xyzx, R5.xyzx;" " RSQ R2.x, R2.x;" " MUL R5.xyz, R2.x, R5.xyzx;" " MAD R1.yzw, R1.x, R1.yyzw, R5.xxyz;" " DP3 R1.x, R1.yzwy, R1.yzwy;" " RSQ R1.x, R1.x;" " MUL R4.xyz, R1.x, R1.yzwy;" " DP3 R3.x, R0.xyzx, v3.xyzx;" " DP3 R3.y, R7.xyzx, v3.xyzx;" " DP3 R3.z, R6.xyzx, v3.xyzx;" " DP3 R8.x, R3.xyzx, R4.xyzx;" " DP3 R2.x, R0.xyzx, v4.xyzx;" " DP3 R2.y, R7.xyzx, v4.xyzx;" " DP3 R2.z, R6.xyzx, v4.xyzx;" " DP3 R8.y, R2.xyzx, R4.xyzx;" " DP3 R1.x, R0.xyzx, v5.xyzx;" " DP3 R1.y, R7.xyzx, v5.xyzx;" " DP3 R1.z, R6.xyzx, v5.xyzx;" " DP3 R8.z, R1.xyzx, R4.xyzx;" " MAD result.color.front.secondary.xyz, c5.x, R8.xyzx, c5.x;" " DP3 R0.y, R0.xyzx, v18.xyzx;" " DP3 R0.z, R7.xyzx, v18.xyzx;" " DP3 R0.w, R6.xyzx, v18.xyzx;" " DP3 R0.x, R0.yzwy, R0.yzwy;" " RSQ R0.x, R0.x;" " MUL R6.xyz, R0.x, R0.yzwy;" " DP3 R0.x, R6.xyzx, R4.xyzx;" " MUL result.color.front.secondary.w, c5.y, R0.x;" " DP3 R0.x, R3.xyzx, R5.xyzx;" " DP3 R0.y, R2.xyzx, R5.xyzx;" " DP3 R0.z, R1.xyzx, R5.xyzx;" " MAD result.color.front.primary.xyz, c5.x, R0.xyzx, c5.x;" " DP3 R0.x, R6.xyzx, R5.xyzx;" " MUL result.color.front.primary.w, c5.y, R0.x;" "END\n"; // fragment program std::ostringstream fp_oss; fp_oss << "!!ARBfp1.0\n" "PARAM c0 = {1, 2, 0.5, 0};" "PARAM c1 = {0, 0, 0, 1};" "TEMP R0;" "TEMP R1;" "TEMP R2;" "TEX R0, fragment.texcoord[" << _normal_unit << "], texture[" << _normal_unit << "], 2D;" "TEX R1, fragment.texcoord[" << _diffuse_unit << "], texture[" << _diffuse_unit << "], 2D;" "ADD R0, R0, -c0.z;" "MUL R0.xyz, c0.y, R0;" "ADD R2.xyz, fragment.color.primary, -c0.z;" "MUL R2.xyz, c0.y, R2;" "DP3_SAT R0.w, R0, R2;" "ADD R2, fragment.color.secondary, -c0.z;" "MUL R2.xyz, c0.y, R2;" "DP3_SAT R0.x, R0, R2;" "POW R0.x, R0.x, fragment.texcoord[" << freeunit << "].w;" "MOV R2.xyz, fragment.texcoord[" << freeunit << "].xyyx;" "MOV R2.w, c1.w;" "MOV_SAT R0.y, fragment.color.primary.w;" "MUL R0.w, R0.y, R0.w;" "ADD R2, R2, R0.w;" "MUL R1.xyz, R1, R2;" "MOV_SAT R0.y, fragment.color.secondary.w;" "MUL R0.xyz, R0.y, R0.x;" "MOV R2.xy, fragment.texcoord[" << _diffuse_unit << "].zwzz;" "MOV R2.z, fragment.texcoord[" << _normal_unit << "].z;" "MUL R2.xyz, R0, R2;" "ADD R2.xyz, R1, R2;" "MOV result.color.xyz, R2;" "MOV result.color.w, c0.x;" "END\n"; osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr vp = new osg::VertexProgram; vp->setVertexProgram(vp_oss.str()); ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr fp = new osg::FragmentProgram; fp->setFragmentProgram(fp_oss.str()); ss->setAttributeAndModes(fp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); if (_diffuse_tex.valid()) { ss->setTextureAttributeAndModes(_diffuse_unit, _diffuse_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); } if (_normal_tex.valid()) { ss->setTextureAttributeAndModes(_normal_unit, _normal_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); } addPass(ss.get()); } private: int _lightnum; int _diffuse_unit; int _normal_unit; osg::ref_ptr _diffuse_tex; osg::ref_ptr _normal_tex; }; } namespace { // "ARB Vp" technique uses ARB vertex program and DOT3 texture environment. // Ambient and specular components are not handled. A texture for the diffuse // component is required as well as a normal map texture. class ArbVpTechnique: public Technique { public: ArbVpTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D* diffuse_tex, osg::Texture2D* normal_tex) : Technique(), _lightnum(lightnum), _diffuse_unit(diffuseunit), _normal_unit(normalunit), _diffuse_tex(diffuse_tex), _normal_tex(normal_tex) { } META_Technique( "ArbVpTechnique", "Two-passes technique, requires ARB_vertex_program and ARB__textureenv_dot3." "Only diffuse lighting, no ambient, no specularity." ); void getRequiredExtensions(std::vector& extensions) const { extensions.push_back("GL_ARB_vertex_program"); extensions.push_back("GL_ARB_texture_env_dot3"); } void define_passes() { if (_diffuse_unit != (_normal_unit + 1)) { OSG_WARN << "Warning: osgFX::BumpMapping: this technique (ArbVpTechnique) requires that _diffuse_unit == (_normal_unit + 1). Effect may not show up properly.\n"; } // first pass, diffuse bump { std::ostringstream vp_oss; vp_oss << "!!ARBvp1.0\n" "OPTION ARB_position_invariant;" "PARAM c0 = { 0.5, 1, 0, 0 };" "TEMP R0, R1, R2;" "ATTRIB v5 = vertex.attrib[15];" "ATTRIB v4 = vertex.attrib[7];" "ATTRIB v3 = vertex.attrib[6];" "ATTRIB v24 = vertex.texcoord[" << _normal_unit << "];" "ATTRIB v25 = vertex.texcoord[" << _diffuse_unit << "];" "ATTRIB v18 = vertex.normal;" "ATTRIB v16 = vertex.position;" "PARAM s259[4] = { state.matrix.mvp };" "PARAM s18 = state.light[" << _lightnum << "].position;" "PARAM s223[4] = { state.matrix.modelview };" " MOV result.texcoord[" << _diffuse_unit << "].xy, v25;" " MOV result.texcoord[" << _normal_unit << "].xy, v24;" " DP3 R0.y, s223[0].xyzx, v3.xyzx;" " DP3 R0.z, s223[1].xyzx, v3.xyzx;" " DP3 R0.w, s223[2].xyzx, v3.xyzx;" " DP3 R0.x, s18.xyzx, s18.xyzx;" " RSQ R0.x, R0.x;" " MUL R2.xyz, R0.x, s18.xyzx;" " DP3 R1.x, R0.yzwy, R2.xyzx;" " DP3 R0.x, s223[0].xyzx, v4.xyzx;" " DP3 R0.y, s223[1].xyzx, v4.xyzx;" " DP3 R0.z, s223[2].xyzx, v4.xyzx;" " DP3 R1.y, R0.xyzx, R2.xyzx;" " DP3 R0.x, s223[0].xyzx, v5.xyzx;" " DP3 R0.y, s223[1].xyzx, v5.xyzx;" " DP3 R0.z, s223[2].xyzx, v5.xyzx;" " DP3 R1.z, R0.xyzx, R2.xyzx;" " MAD result.color.front.primary.xyz, c0.x, R1.xyzx, c0.x;" " MOV result.color.front.primary.w, c0.y;" "END\n"; osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr vp = new osg::VertexProgram; vp->setVertexProgram(vp_oss.str()); ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); if (_diffuse_tex.valid()) { ss->setTextureAttributeAndModes(_diffuse_unit, _diffuse_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); } if (_normal_tex.valid()) { ss->setTextureAttributeAndModes(_normal_unit, _normal_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); } osg::ref_ptr tec = new osg::TexEnvCombine; tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB); tec->setSource0_RGB(osg::TexEnvCombine::PRIMARY_COLOR); tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE); ss->setTextureAttributeAndModes(_normal_unit, tec.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr te = new osg::TexEnv; te->setMode(osg::TexEnv::MODULATE); ss->setTextureAttributeAndModes(_diffuse_unit, te.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); addPass(ss.get()); } // second pass, self-shadowing bool selfShadowing = false; if (selfShadowing) { std::ostringstream vp_oss; vp_oss << "!!ARBvp1.0\n" "OPTION ARB_position_invariant;" "PARAM c0 = { 8, 0, 1, 0 };" "TEMP R0;" "ATTRIB v18 = vertex.normal;" "ATTRIB v16 = vertex.position;" "PARAM s259[4] = { state.matrix.mvp };" "PARAM s18 = state.light[" << _lightnum << "].position;" "PARAM s631[4] = { state.matrix.modelview.invtrans };" " DP4 R0.x, s631[0], v18;" " DP4 R0.y, s631[1], v18;" " DP4 R0.z, s631[2], v18;" " DP3 R0.x, R0.xyzx, s18.xyzx;" " MAX R0.x, R0.x, c0.y;" " MUL R0.x, c0.x, R0.x;" " MIN result.color.front.primary.xyz, R0.x, c0.z;" " MOV result.color.front.primary.w, c0.z;" "END\n"; osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr depth = new osg::Depth; depth->setFunction(osg::Depth::EQUAL); ss->setAttributeAndModes(depth.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr vp = new osg::VertexProgram; vp->setVertexProgram(vp_oss.str()); ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr bf = new osg::BlendFunc; bf->setFunction(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO); ss->setAttributeAndModes(bf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setTextureMode(_diffuse_unit, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); ss->setTextureMode(_normal_unit, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); addPass(ss.get()); } } protected: int _lightnum; int _diffuse_unit; int _normal_unit; osg::ref_ptr _diffuse_tex; osg::ref_ptr _normal_tex; }; } BumpMapping::BumpMapping() : Effect(), _lightnum(0), _diffuse_unit(1), _normal_unit(0) { } BumpMapping::BumpMapping(const BumpMapping& copy, const osg::CopyOp& copyop) : Effect(copy, copyop), _lightnum(copy._lightnum), _diffuse_unit(copy._diffuse_unit), _normal_unit(copy._normal_unit), _diffuse_tex(static_cast(copyop(copy._diffuse_tex.get()))), _normal_tex(static_cast(copyop(copy._normal_tex.get()))) { } bool BumpMapping::define_techniques() { addTechnique(new FullArbTechnique(_lightnum, _diffuse_unit, _normal_unit, _diffuse_tex.get(), _normal_tex.get())); addTechnique(new ArbVpTechnique(_lightnum, _diffuse_unit, _normal_unit, _diffuse_tex.get(), _normal_tex.get())); return true; } void BumpMapping::prepareGeometry(osg::Geometry* geo) { osg::ref_ptr tsg = new osgUtil::TangentSpaceGenerator; tsg->generate(geo, _normal_unit); if (!geo->getVertexAttribArray(6)) geo->setVertexAttribArray(6, tsg->getTangentArray()); if (!geo->getVertexAttribArray(7)) geo->setVertexAttribArray(7, tsg->getBinormalArray()); if (!geo->getVertexAttribArray(15)) geo->setVertexAttribArray(15, tsg->getNormalArray()); } void BumpMapping::prepareNode(osg::Node* node) { osg::ref_ptr tv = new TsgVisitor(this); node->accept(*tv.get()); } void BumpMapping::prepareChildren() { for (unsigned i=0; iaccept(tcg); // set up diffuse texture if (!_diffuse_tex.valid()) { _diffuse_tex = new osg::Texture2D; _diffuse_tex->setImage(osgDB::readRefImageFile("Images/whitemetal_diffuse.jpg")); _diffuse_tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); _diffuse_tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); _diffuse_tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); _diffuse_tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); _diffuse_tex->setMaxAnisotropy(8); } // set up normal map texture if (!_normal_tex.valid()) { _normal_tex = new osg::Texture2D; _normal_tex->setImage(osgDB::readRefImageFile("Images/whitemetal_normal.jpg")); _normal_tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); _normal_tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); _normal_tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); _normal_tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); _normal_tex->setMaxAnisotropy(8); } // generate tangent-space basis vector prepareChildren(); // recreate techniques on next step dirtyTechniques(); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Validator.cpp0000644000175000017500000000220213151044751023324 0ustar albertoalberto#include #include #include using namespace osgFX; Validator::Validator() : osg::StateAttribute(), _effect(0) { } Validator::Validator(Effect* effect) : osg::StateAttribute(), _effect(effect) { } Validator::Validator(const Validator& copy, const osg::CopyOp& copyop) : osg::StateAttribute(copy, copyop), _effect(static_cast(copyop(copy._effect))) { } void Validator::compileGLObjects(osg::State& state) const { apply(state); } void Validator::apply(osg::State& state) const { if (!_effect) return; if (_effect->_tech_selected[state.getContextID()] == 0) { Effect::Technique_list::iterator i; int j = 0; for (i=_effect->_techs.begin(); i!=_effect->_techs.end(); ++i, ++j) { if ((*i)->validate(state)) { _effect->_sel_tech[state.getContextID()] = j; _effect->_tech_selected[state.getContextID()] = 1; return; } } OSG_WARN << "Warning: osgFX::Validator: could not find any techniques compatible with the current OpenGL context" << std::endl; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Registry.cpp0000644000175000017500000000031313151044751023210 0ustar albertoalberto#include using namespace osgFX; Registry* Registry::instance() { static osg::ref_ptr s_instance = new Registry; return s_instance.get(); } Registry::Registry() { } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Effect.cpp0000644000175000017500000000762313151044751022607 0ustar albertoalberto#include #include #include #include #include #include #include using namespace osgFX; Effect::Effect() : osg::Group(), _enabled(true), _global_sel_tech(AUTO_DETECT), _techs_defined(false) { build_dummy_node(); } Effect::Effect(const Effect& copy, const osg::CopyOp& copyop) : osg::Group(copy, copyop), _enabled(copy._enabled), _global_sel_tech(copy._global_sel_tech), _techs_defined(false) { build_dummy_node(); } Effect::~Effect() { // disable the validator for safety, so it won't try to access us // even if it stays alive for some reason if (_dummy_for_validation.valid()) { osg::StateSet* ss = _dummy_for_validation->getStateSet(); if (ss) { Validator *validator = dynamic_cast(ss->getAttribute(Validator::VALIDATOR)); if (validator) { validator->disable(); } } } } void Effect::traverse(osg::NodeVisitor& nv) { // if this effect is not enabled, then go for default traversal if (!_enabled) { inherited_traverse(nv); return; } // ensure that at least one technique is defined if (!_techs_defined) { // clear existing techniques _techs.clear(); // clear technique selection indices _sel_tech.clear(); // clear technique selection flags _tech_selected.clear(); // define new techniques _techs_defined = define_techniques(); // check for errors, return on failure if (!_techs_defined) { OSG_WARN << "Warning: osgFX::Effect: could not define techniques for effect " << className() << std::endl; return; } // ensure that at least one technique has been defined if (_techs.empty()) { OSG_WARN << "Warning: osgFX::Effect: no techniques defined for effect " << className() << std::endl; return; } } Technique *tech = 0; // if the selection mode is set to AUTO_DETECT then we have to // choose the active technique! if (_global_sel_tech == AUTO_DETECT) { // test whether at least one technique has been selected bool none_selected = true; for (unsigned i=0; i<_tech_selected.size(); ++i) { if (_tech_selected[i] != 0) { none_selected = false; break; } } // no techniques selected, traverse a dummy node that // contains the Validator (it will select a technique) if (none_selected) { _dummy_for_validation->accept(nv); } // find the highest priority technique that could be validated // in all active rendering contexts int max_index = -1; for (unsigned j=0; j<_sel_tech.size(); ++j) { if (_tech_selected[j] != 0) { if (_sel_tech[j] > max_index) { max_index = _sel_tech[j]; } } } // found a valid technique? if (max_index >= 0) { tech = _techs[max_index].get(); } } else { // the active technique was selected manually tech = _techs[_global_sel_tech].get(); } // if we could find an active technique, then continue with traversal, // else go for default traversal (no effect) if (tech) { tech->traverse(nv, this); } else { if (nv.getTraversalMode() == osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { inherited_traverse(nv); } } // wow, we're finished! :) } void Effect::build_dummy_node() { _dummy_for_validation = new osg::Geode; osg::ref_ptr geo = new osg::Geometry; _dummy_for_validation->addDrawable(geo.get()); _dummy_for_validation->getOrCreateStateSet()->setAttribute(new Validator(this)); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/CMakeLists.txt0000644000175000017500000000204413151044751023437 0ustar albertoalberto IF(DYNAMIC_OPENSCENEGRAPH) ADD_DEFINITIONS(-DOSGFX_LIBRARY) ELSE() ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) ENDIF() SET(LIB_NAME osgFX) SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) SET(TARGET_H ${HEADER_PATH}/AnisotropicLighting ${HEADER_PATH}/BumpMapping ${HEADER_PATH}/Cartoon ${HEADER_PATH}/Effect ${HEADER_PATH}/Export ${HEADER_PATH}/MultiTextureControl ${HEADER_PATH}/Outline ${HEADER_PATH}/Registry ${HEADER_PATH}/Scribe ${HEADER_PATH}/SpecularHighlights ${HEADER_PATH}/Technique ${HEADER_PATH}/Validator ${HEADER_PATH}/Version ) # FIXME: For OS X, need flag for Framework or dylib SET(TARGET_SRC AnisotropicLighting.cpp BumpMapping.cpp Cartoon.cpp Effect.cpp MultiTextureControl.cpp Outline.cpp Registry.cpp Scribe.cpp SpecularHighlights.cpp Technique.cpp Validator.cpp Version.cpp ${OPENSCENEGRAPH_VERSIONINFO_RC} ) SET(TARGET_LIBRARIES osgUtil osgDB osg OpenThreads ) SETUP_LIBRARY(${LIB_NAME}) OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/SpecularHighlights.cpp0000644000175000017500000001333213151044751025176 0ustar albertoalberto#include #include #include #include #include #include #include using namespace osgFX; namespace { class AutoTextureMatrix: public osg::StateAttribute { public: AutoTextureMatrix() : osg::StateAttribute(), _lightnum(0), _active(false) { } AutoTextureMatrix(const AutoTextureMatrix& copy, const osg::CopyOp& copyop) : osg::StateAttribute(copy, copyop), _lightnum(copy._lightnum), _active(copy._active) { } AutoTextureMatrix(int lightnum, bool active = true) : osg::StateAttribute(), _lightnum(lightnum), _active(active) { } META_StateAttribute(osgFX, AutoTextureMatrix, osg::StateAttribute::TEXMAT); virtual bool isTextureAttribute() const { return true; } int compare(const osg::StateAttribute &sa) const { COMPARE_StateAttribute_Types(AutoTextureMatrix, sa); if (_lightnum < rhs._lightnum) return -1; if (_lightnum > rhs._lightnum) return 1; return 0; } void apply(osg::State& state) const { #ifdef OSG_GL_MATRICES_AVAILABLE glMatrixMode(GL_TEXTURE); if (_active) { osg::Matrix M = state.getInitialViewMatrix(); M(3, 0) = 0; M(3, 1) = 0; M(3, 2) = 0; M(3, 3) = 1; M(0, 3) = 0; M(1, 3) = 0; M(2, 3) = 0; osg::Vec4 lightvec; glGetLightfv(GL_LIGHT0+_lightnum, GL_POSITION, lightvec._v); osg::Vec3 eye_light_ref = osg::Vec3(0, 0, 1) * M; osg::Matrix LM = osg::Matrix::rotate( osg::Vec3(lightvec.x(), lightvec.y(), lightvec.z()), eye_light_ref); glLoadMatrix((LM * osg::Matrix::inverse(M)).ptr()); } else { glLoadIdentity(); } glMatrixMode(GL_MODELVIEW); #else OSG_NOTICE<<"Warning: osgFX::SpecualHighlights unable to set texture matrix."<& extensions) { extensions.push_back("GL_ARB_texture_env_add"); } bool validate(osg::State& state) const { if (!Technique::validate(state)) return false; osg::GLExtensions *ext = state.get(); return ext ? ext->isCubeMapSupported : false; } protected: void define_passes() { osg::ref_ptr ss = new osg::StateSet; ss->setTextureAttributeAndModes(_unit, new AutoTextureMatrix(_lightnum), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr hmg = new osgUtil::HighlightMapGenerator(osg::Vec3(0, 0, -1), _color, _sexp); hmg->generateMap(false); osg::ref_ptr texture = new osg::TextureCubeMap; texture->setImage(osg::TextureCubeMap::POSITIVE_X, hmg->getImage(osg::TextureCubeMap::POSITIVE_X)); texture->setImage(osg::TextureCubeMap::POSITIVE_Y, hmg->getImage(osg::TextureCubeMap::POSITIVE_Y)); texture->setImage(osg::TextureCubeMap::POSITIVE_Z, hmg->getImage(osg::TextureCubeMap::POSITIVE_Z)); texture->setImage(osg::TextureCubeMap::NEGATIVE_X, hmg->getImage(osg::TextureCubeMap::NEGATIVE_X)); texture->setImage(osg::TextureCubeMap::NEGATIVE_Y, hmg->getImage(osg::TextureCubeMap::NEGATIVE_Y)); texture->setImage(osg::TextureCubeMap::NEGATIVE_Z, hmg->getImage(osg::TextureCubeMap::NEGATIVE_Z)); texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE); ss->setTextureAttributeAndModes(_unit, texture.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr texgen = new osg::TexGen; texgen->setMode(osg::TexGen::REFLECTION_MAP); ss->setTextureAttributeAndModes(_unit, texgen.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr texenv = new osg::TexEnv; texenv->setMode(osg::TexEnv::ADD); ss->setTextureAttributeAndModes(_unit, texenv.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); addPass(ss.get()); } private: int _lightnum; int _unit; osg::Vec4 _color; float _sexp; }; } SpecularHighlights::SpecularHighlights() : Effect(), _lightnum(0), _unit(0), _color(1, 1, 1, 1), _sexp(16) { } SpecularHighlights::SpecularHighlights(const SpecularHighlights& copy, const osg::CopyOp& copyop) : Effect(copy, copyop), _lightnum(copy._lightnum), _unit(copy._unit), _color(copy._color), _sexp(copy._sexp) { } bool SpecularHighlights::define_techniques() { addTechnique(new DefaultTechnique(_lightnum, _unit, _color, _sexp)); return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Technique.cpp0000644000175000017500000000317713151044751023340 0ustar albertoalberto#include #include #include #include using namespace osgFX; Technique::Technique() : osg::Referenced() { } void Technique::addPass(osg::StateSet* ss) { if (ss) { _passes.push_back(ss); ss->setRenderBinDetails(static_cast(_passes.size()), "RenderBin"); } } bool Technique::validate(osg::State& state) const { typedef std::vector String_list; String_list extensions; getRequiredExtensions(extensions); for (String_list::const_iterator i=extensions.begin(); i!=extensions.end(); ++i) { if (!osg::isGLExtensionSupported(state.getContextID(),i->c_str())) return false; } return true; } void Technique::traverse_implementation(osg::NodeVisitor& nv, Effect* fx) { // define passes if necessary if (_passes.empty()) { define_passes(); } // special actions must be taken if the node visitor is actually a CullVisitor osgUtil::CullVisitor *cv = dynamic_cast(&nv); // traverse all passes for (int i=0; ipushStateSet(_passes[i].get()); } // traverse the override node if defined, otherwise // traverse children as a Group would do osg::Node *override = getOverrideChild(i); if (override) { override->accept(nv); } else { fx->inherited_traverse(nv); } // pop the StateSet if necessary if (cv) { cv->popStateSet(); } } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/MultiTextureControl.cpp0000644000175000017500000001510313151044751025417 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osg; using namespace osgFX; MultiTextureControl::MultiTextureControl(): _useTexEnvCombine(true), _useTextureWeightsUniform(true) { _textureWeights = new TextureWeights; } MultiTextureControl::MultiTextureControl(const MultiTextureControl& copy, const osg::CopyOp& copyop): Group(copy,copyop), _textureWeights(osg::clone(copy._textureWeights.get(), osg::CopyOp::DEEP_COPY_ALL)), _useTexEnvCombine(copy._useTexEnvCombine), _useTextureWeightsUniform(copy._useTextureWeightsUniform) { updateStateSet(); } void MultiTextureControl::setTextureWeight(unsigned int unit, float weight) { if (unit >= _textureWeights->size()) { _textureWeights->resize(unit+1,0.0f); } (*_textureWeights)[unit] = weight; updateStateSet(); } void MultiTextureControl::updateStateSet() { osg::ref_ptr stateset = new osg::StateSet; if (_useTexEnvCombine) { unsigned int numTextureUnitsOn = 0; unsigned int unit; for(unit=0;unit<_textureWeights->size();++unit) { if ((*_textureWeights)[unit]>0.0f) ++numTextureUnitsOn; } if (numTextureUnitsOn<=1) { for(unit=0;unit<_textureWeights->size();++unit) { if ((*_textureWeights)[unit]>0.0f) { osg::TexEnv* texenv = new osg::TexEnv(osg::TexEnv::MODULATE); stateset->setTextureAttribute(unit, texenv); stateset->setTextureMode(unit, GL_TEXTURE_2D, osg::StateAttribute::ON); } else { stateset->setTextureMode(unit, GL_TEXTURE_2D, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } } } else if (_textureWeights->size()==2) { { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+0); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource2_RGB(osg::TexEnvCombine::CONSTANT); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); float r = (*_textureWeights)[0]/((*_textureWeights)[0]+(*_textureWeights)[1]); texenv->setConstantColor(osg::Vec4(r,r,r,r)); stateset->setTextureAttribute(0, texenv); } { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); stateset->setTextureAttribute(1, texenv); } } else if (_textureWeights->size()==3) { float b = ((*_textureWeights)[0]+(*_textureWeights)[1])/((*_textureWeights)[0]+(*_textureWeights)[1]+(*_textureWeights)[2]); float a = (*_textureWeights)[0]/((*_textureWeights)[0]+(*_textureWeights)[1]); { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+0); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE0+1); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource2_RGB(osg::TexEnvCombine::CONSTANT); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setConstantColor(osg::Vec4(a,a,a,a)); stateset->setTextureAttribute(0, texenv); } { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE0+2); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource2_RGB(osg::TexEnvCombine::CONSTANT); texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setConstantColor(osg::Vec4(b,b,b,b)); stateset->setTextureAttribute(1, texenv); } { osg::TexEnvCombine* texenv = new osg::TexEnvCombine; texenv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); texenv->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR); texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); stateset->setTextureAttribute(2, texenv); } } } if (_useTextureWeightsUniform && _textureWeights->size()>0) { osg::ref_ptr uniform = new osg::Uniform(osg::Uniform::FLOAT, "TextureWeights", _textureWeights->size()); #if 1 uniform->setArray(_textureWeights.get()); #else for(unsigned int i=0; i<_textureWeights->size(); ++i) { uniform->setElement(i, (*_textureWeights)[i]); } #endif stateset->addUniform(uniform.get()); stateset->setDefine("TEXTURE_WEIGHTS"); } setStateSet(stateset.get()); } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/Outline.cpp0000644000175000017500000001372313151044751023030 0ustar albertoalberto// -*-c++-*- /* * OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ /* * osgFX::Outline - Copyright (C) 2004,2009 Ulrich Hertlein */ #include #include #include #include #include #include #include #include #include namespace { const unsigned int Override_On = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE; const unsigned int Override_Off = osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE; } namespace osgFX { /// Register prototype. Registry::Proxy proxy(new Outline); /** * Outline technique. */ class Outline::OutlineTechnique : public Technique { public: /// Constructor. OutlineTechnique() : Technique(), _lineWidth(), _width(2), _material(), _color(1,1,1,1) { } /// Validate. bool validate(osg::State&) const { return true; } /// Set outline width. void setWidth(float w) { _width = w; if (_lineWidth.valid()) { _lineWidth->setWidth(w); } } /// Set outline color. void setColor(const osg::Vec4& color) { _color = color; if (_material.valid()) { const osg::Material::Face face = osg::Material::FRONT_AND_BACK; _material->setAmbient(face, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); _material->setDiffuse(face, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); _material->setSpecular(face, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); _material->setEmission(face, color); } } protected: /// Define render passes. void define_passes() { /* * draw * - set stencil buffer to ref=1 where draw occurs * - clear stencil buffer to 0 where test fails */ { osg::StateSet* state = new osg::StateSet; // stencil op osg::Stencil* stencil = new osg::Stencil; stencil->setFunction(osg::Stencil::ALWAYS, 1, ~0u); stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::REPLACE); state->setAttributeAndModes(stencil, Override_On); addPass(state); } /* * post-draw * - only draw where draw didn't set the stencil buffer * - draw only back-facing polygons * - draw back-facing polys as lines * - disable depth-test, lighting & texture */ { osg::StateSet* state = new osg::StateSet; // stencil op osg::Stencil* stencil = new osg::Stencil; stencil->setFunction(osg::Stencil::NOTEQUAL, 1, ~0u); stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::REPLACE); state->setAttributeAndModes(stencil, Override_On); // cull front-facing polys osg::CullFace* cullFace = new osg::CullFace; cullFace->setMode(osg::CullFace::FRONT); state->setAttributeAndModes(cullFace, Override_On); // draw back-facing polygon lines osg::PolygonMode* polyMode = new osg::PolygonMode; polyMode->setMode(osg::PolygonMode::BACK, osg::PolygonMode::LINE); state->setAttributeAndModes(polyMode, Override_On); // outline width _lineWidth = new osg::LineWidth; setWidth(_width); state->setAttributeAndModes(_lineWidth.get(), Override_On); // outline color/material _material = new osg::Material; _material->setColorMode(osg::Material::OFF); setColor(_color); state->setAttributeAndModes(_material.get(), Override_On); // disable modes state->setMode(GL_BLEND, Override_Off); //state->setMode(GL_DEPTH_TEST, Override_Off); state->setTextureMode(0, GL_TEXTURE_1D, Override_Off); state->setTextureMode(0, GL_TEXTURE_2D, Override_Off); state->setTextureMode(0, GL_TEXTURE_3D, Override_Off); addPass(state); } } private: /// Outline width. osg::ref_ptr _lineWidth; float _width; /// Outline Material. osg::ref_ptr _material; osg::Vec4 _color; }; /** * Outline effect. */ Outline::Outline() : Effect(), _width(2), _color(1,1,1,1), _technique(0) { } void Outline::setWidth(float w) { _width = w; if (_technique) { _technique->setWidth(w); } } void Outline::setColor(const osg::Vec4& color) { _color = color; if (_technique) { _technique->setColor(color); } } bool Outline::define_techniques() { _technique = new OutlineTechnique; addTechnique(_technique); setWidth(_width); setColor(_color); return true; } } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgFX/AnisotropicLighting.cpp0000644000175000017500000002153313151044751025367 0ustar albertoalberto#include #include #include #include #include #include #include using namespace osgFX; namespace { // a state attribute class that grabs the initial inverse view matrix // and sends it to a VertexProgram. // NOTE: due to lack of support for per-context parameters in VertexProgram, // this class will send the matrix to the vp only while the first context // is being rendered. All subsequent contexts will use the first context's // matrix. class ViewMatrixExtractor: public osg::StateAttribute { public: ViewMatrixExtractor() : osg::StateAttribute(), _vp(0), _param(0), _first_context(-1) { } ViewMatrixExtractor(const ViewMatrixExtractor& copy, const osg::CopyOp& copyop) : osg::StateAttribute(copy, copyop), _vp(static_cast(copyop(copy._vp.get()))), _param(copy._param), _first_context(-1) { } ViewMatrixExtractor(osg::VertexProgram *vp, int param) : osg::StateAttribute(), _vp(vp), _param(param), _first_context(-1) { } META_StateAttribute(osgFX, ViewMatrixExtractor, VIEWMATRIXEXTRACTOR); int compare(const osg::StateAttribute &sa) const { COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa); if (_vp.get() != rhs._vp.get()) return -1; if (_param < rhs._param) return -1; if (_param > rhs._param) return 1; return 0; } void apply(osg::State& state) const { if (_first_context == -1) { _first_context = state.getContextID(); } if (state.getContextID() == (unsigned int)_first_context) { if (_vp.valid()) { osg::Matrix M = state.getInitialInverseViewMatrix(); for (int i=0; i<4; ++i) { _vp->setProgramLocalParameter(_param+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i))); } } } } private: mutable osg::ref_ptr _vp; int _param; mutable int _first_context; }; } namespace { osg::Image* create_default_image() { const int _texturesize = 16; osg::ref_ptr image = new osg::Image; image->setImage(_texturesize, _texturesize, 1, 3, GL_RGB, GL_UNSIGNED_BYTE, new unsigned char[3*_texturesize*_texturesize], osg::Image::USE_NEW_DELETE); for (int i=0; i<_texturesize; ++i) { for (int j=0; j<_texturesize; ++j) { float s = static_cast(j) / (_texturesize-1); float t = static_cast(i) / (_texturesize-1); float lum = t * 0.75f; float red = lum + 0.2f * powf(cosf(s*10), 3.0f); float green = lum; float blue = lum + 0.2f * powf(sinf(s*10), 3.0f); if (red > 1) red = 1; if (red < 0) red = 0; if (blue > 1) blue = 1; if (blue < 0) blue = 0; *(image->data(j, i)+0) = static_cast(red * 255); *(image->data(j, i)+1) = static_cast(green * 255); *(image->data(j, i)+2) = static_cast(blue * 255); } } return image.release(); } } namespace { Registry::Proxy proxy(new AnisotropicLighting); class DefaultTechnique: public Technique { public: DefaultTechnique(int lightnum, osg::Texture2D *texture) : Technique(), _lightnum(lightnum), _texture(texture) { } void getRequiredExtensions(std::vector& extensions) const { extensions.push_back("GL_ARB_vertex_program"); } protected: void define_passes() { std::ostringstream vp_oss; vp_oss << "!!ARBvp1.0\n" "PARAM c5 = { 0, 0, 0, 1 };" "PARAM c4 = { 0, 0, 0, 0 };" "TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8, R9;" "ATTRIB v18 = vertex.normal;" "ATTRIB v16 = vertex.position;" "PARAM s259[4] = { state.matrix.mvp };" "PARAM s18 = state.light[" << _lightnum << "].position;" "PARAM s223[4] = { state.matrix.modelview };" "PARAM c0[4] = { program.local[0..3] };" " DP4 result.position.x, s259[0], v16;" " DP4 result.position.y, s259[1], v16;" " DP4 result.position.z, s259[2], v16;" " DP4 result.position.w, s259[3], v16;" " MOV R9, c0[0];" " MUL R0, R9.y, s223[1];" " MAD R0, R9.x, s223[0], R0;" " MAD R0, R9.z, s223[2], R0;" " MAD R8, R9.w, s223[3], R0;" " DP4 R0.x, R8, v16;" " MOV R7, c0[1];" " MUL R1, R7.y, s223[1];" " MAD R1, R7.x, s223[0], R1;" " MAD R1, R7.z, s223[2], R1;" " MAD R6, R7.w, s223[3], R1;" " DP4 R0.y, R6, v16;" " MOV R5, c0[2];" " MUL R1, R5.y, s223[1];" " MAD R1, R5.x, s223[0], R1;" " MAD R1, R5.z, s223[2], R1;" " MAD R4, R5.w, s223[3], R1;" " DP4 R0.z, R4, v16;" " MOV R3, c0[3];" " MUL R1, R3.y, s223[1];" " MAD R1, R3.x, s223[0], R1;" " MAD R1, R3.z, s223[2], R1;" " MAD R1, R3.w, s223[3], R1;" " DP4 R0.w, R1, v16;" " MOV R1.x, R9.w;" " MOV R1.y, R7.w;" " MOV R1.z, R5.w;" " MOV R1.w, R3.w;" " ADD R2, R1, -R0;" " DP4 R0.x, R2, R2;" " RSQ R1.x, R0.x;" " DP4 R0.x, R9, s18;" " DP4 R0.y, R7, s18;" " DP4 R0.z, R5, s18;" " DP4 R0.w, R3, s18;" " DP4 R1.y, R0, R0;" " RSQ R1.y, R1.y;" " MUL R3, R1.y, R0;" " MAD R2, R1.x, R2, R3;" " DP4 R1.x, R2, R2;" " RSQ R1.x, R1.x;" " MUL R1, R1.x, R2;" " DP3 R2.x, R8.xyzx, v18.xyzx;" " DP3 R2.y, R6.xyzx, v18.xyzx;" " DP3 R2.z, R4.xyzx, v18.xyzx;" " MOV R2.w, c4.x;" " DP4 R1.x, R1, R2;" " MAX result.texcoord[0].x, R1.x, c4.x;" " DP4 R0.x, R0, R2;" " MAX result.texcoord[0].y, R0.x, c4.x;" "END\n"; osg::ref_ptr ss = new osg::StateSet; osg::ref_ptr vp = new osg::VertexProgram; vp->setVertexProgram(vp_oss.str()); ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); ss->setTextureAttributeAndModes(0, _texture.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); osg::ref_ptr texenv = new osg::TexEnv; texenv->setMode(osg::TexEnv::DECAL); ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); #if !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) ss->setMode( GL_ALPHA_TEST, osg::StateAttribute::OFF ); #else OSG_NOTICE<<"Warning: osgFX::AnisotropicLighting unable to disable GL_ALPHA_TEST."< _texture; }; } AnisotropicLighting::AnisotropicLighting() : Effect(), _lightnum(0), _texture(new osg::Texture2D) { _texture->setImage(create_default_image()); _texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP); _texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP); } AnisotropicLighting::AnisotropicLighting(const AnisotropicLighting& copy, const osg::CopyOp& copyop) : Effect(copy, copyop), _lightnum(copy._lightnum), _texture(static_cast(copyop(copy._texture.get()))) { } bool AnisotropicLighting::define_techniques() { addTechnique(new DefaultTechnique(_lightnum, _texture.get())); return true; } OpenSceneGraph-OpenSceneGraph-3.4.1/src/osgUI/0000755000175000017500000000000013151044751020677 5ustar albertoalbertoOpenSceneGraph-OpenSceneGraph-3.4.1/src/osgUI/Style.cpp0000644000175000017500000004364613151044751022520 0ustar albertoalberto/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgUI; osg::ref_ptr